diff --git a/.gitignore b/.gitignore index 7c99f0a..3d7cc77 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ -Mac/Bungloo.app -Mac/bungloo +Mac/build/ +Mac/Bungloo.xcodeproj/project.xcworkspace/xcuserdata/jeena.xcuserdatad/UserInterfaceState.xcuserstate dsa_priv.pem *.pyc .DS_Store *~ -Linux/dist -Windows/bungloo +Linux/build/ diff --git a/LICENSE.txt b/LICENCE.txt similarity index 100% rename from LICENSE.txt rename to LICENCE.txt diff --git a/Qt/Bungloo.py b/Linux/Bungloo.py similarity index 64% rename from Qt/Bungloo.py rename to Linux/Bungloo.py index e76061f..3c357f8 100755 --- a/Qt/Bungloo.py +++ b/Linux/Bungloo.py @@ -1,22 +1,19 @@ #!/usr/bin/env python2 -import os, sys, pickle, subprocess, shutil, json -from PyQt4 import QtCore, QtGui, QtWebKit, QtNetwork -from sys import platform as _platform +import os, sys, pickle, subprocess, shutil +from PyQt4 import QtCore, QtGui, QtWebKit -try: - import Windows, Helper, SingleApplication -except: - from bungloo import Windows, Helper, SingleApplication +RUNNING_LOCAL = os.path.basename(__file__) == "Bungloo.py" -class Bungloo(): +if RUNNING_LOCAL: + import Windows, Helper +else: + from bungloo import Windows, Helper + +class Bungloo: def __init__(self): - - sslConfig = QtNetwork.QSslConfiguration.defaultConfiguration() - sslConfig.setProtocol(QtNetwork.QSsl.TlsV1) - QtNetwork.QSslConfiguration.setDefaultConfiguration(sslConfig) - + self.app = QtGui.QApplication(sys.argv) self.new_message_windows = [] self.controller = Controller(self) self.console = Console() @@ -25,14 +22,15 @@ class Bungloo(): self.preferences.show() self.oauth_implementation = Windows.Oauth(self) - self.conversation_views = [] if self.controller.stringForKey("user_access_token") != "": self.authentification_succeded() + self.app.exec_() + def resources_path(self): - if Helper.Helper.is_local() and not Helper.Helper.is_mac(): - return os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), '..')) + if RUNNING_LOCAL: + return os.path.abspath(os.path.join(os.path.dirname(__file__), '..')) else: return Helper.Helper.get_resource_path() @@ -85,23 +83,8 @@ class Bungloo(): self.oauth_implementation.log_out() self.timeline.hide() self.preferences.show() - self.timeline.evaluateJavaScript("bungloo.sidebar.logout();") + self.timeline.evaluateJavaScript("bungloo.sidebar.logout()") - def next_show(self): - self.timeline.evaluateJavaScript("bungloo.sidebar.showContentForNext();") - - def handleMessage(self, args): - # argv is just a array of words which you can get in from the outside - argv = json.loads(str(args)) - print args - if len(argv) > 0: - if argv[0] == "--new-message": - text = " ".join(argv[1:]) - self.controller.openNewMessageWidow(text) - elif argv[0].startswith("bungloo://oauthtoken"): - self.oauth_implementation.bungloo_callback(QtCore.QUrl(argv[0].encode("utf-8"), QtCore.QUrl.TolerantMode)) - - class Controller(QtCore.QObject): @@ -109,12 +92,15 @@ class Controller(QtCore.QObject): QtCore.QObject.__init__(self) self.app = app - name = "bungloo2" + oldpath = os.path.expanduser('~/.bungloo/') + if os.path.isdir(oldpath): + shutil.copytree(oldpath, os.path.expanduser('~/.config/bungloo/')) + shutil.rmtree(os.path.expanduser('~/.bungloo/')) - if not os.path.exists(os.path.expanduser("~/.config/" + name + "/")): - os.makedirs(os.path.expanduser("~/.config/" + name + "/")) + if not os.path.exists(os.path.expanduser("~/.config/bungloo/")): + os.makedirs(os.path.expanduser("~/.config/bungloo/")) - self.config_path = os.path.expanduser('~/.config/' + name + '/bungloo.cfg') + self.config_path = os.path.expanduser('~/.config/bungloo/bungloo.cfg') if os.access(self.config_path, os.R_OK): with open(self.config_path, 'r') as f: @@ -165,27 +151,28 @@ class Controller(QtCore.QObject): @QtCore.pyqtSlot(str, str, str, str) def notificateUserAboutMentionFromNameWithPostIdAndEntity(self, text, name, post_id, entity): try: - subprocess.check_output(['kdialog', '--passivepopup', (name + ' mentioned you: ' + text).replace("\"", "\\\"")]) + subprocess.check_output(['kdialog', '--passivepopup', name + ' mentioned you: ' + text]) except OSError: try: - subprocess.check_output(['notify-send', '-i', 'dialog-information', name.replace("\"", "\\\"") + ' mentioned you on Tent', text.replace("\"", "\\\"")]) + subprocess.check_output(['notify-send', '-i', 'dialog-information', name + ' mentioned you on Tent', text]) except OSError: pass - @QtCore.pyqtSlot() - def openNewMessageWidow(self, text=""): - self.openNewMessageWindowInReplyToStatus("") # FIXME: create a status_string with this content - @QtCore.pyqtSlot(str) - def openNewMessageWindowInReplyToStatus(self, status_string): - new_message_window = Windows.NewPost(self.app, status_string) + def openNewMessageWidow(self, string): + new_message_window = Windows.NewPost(self.app) new_message_window.show() new_message_window.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.app.new_message_windows.append(new_message_window) - new_message_window.activateWindow() - new_message_window.setFocus() + + @QtCore.pyqtSlot(str, str, str, bool) + def openNewMessageWindowInReplyTostatusIdwithStringIsPrivate(self, entity, status_id, string, is_private): + new_message_window = Windows.NewPost(self.app) + new_message_window.inReplyToStatusIdWithString(entity, status_id, string) + new_message_window.setIsPrivate(is_private) new_message_window.show() - new_message_window.raise_() + new_message_window.setAttribute(QtCore.Qt.WA_DeleteOnClose) + self.app.new_message_windows.append(new_message_window) def sendMessage(self, message): text = message.text @@ -225,16 +212,6 @@ class Controller(QtCore.QObject): self.app.timeline.evaluateJavaScript(func) self.app.timeline.show() - @QtCore.pyqtSlot(str, str) - def showConversationViewForPostIdandEntity(self, postId, entity): - custom_after_load = "function HostAppGo() { start('conversation-standalone', function() { bungloo.conversation.showStatus(" - custom_after_load += "'{}', '{}'".format(postId, entity) - custom_after_load += "); }) }" - - conversation = Windows.Timeline(self.app, "conversation", "Conversation", custom_after_load) - self.app.conversation_views += [conversation] - conversation.show() - @QtCore.pyqtSlot(str) def showProfileForEntity(self, entity): func = "bungloo.sidebar.onEntityProfile(); bungloo.entityProfile.showProfileForEntity('{}');".format(entity) @@ -263,16 +240,6 @@ class Controller(QtCore.QObject): msgBox.setInformativeText(message) msgBox.exec_() - @QtCore.pyqtSlot(result=str) - def getCachedProfiles(self): - entities = self.app.timeline.evaluateJavaScript("JSON.stringify(bungloo.cache.profiles);") - return entities.toString() - - @QtCore.pyqtSlot() - def getNewData(self): - func = "bungloo.timeline.getNewData()" - self.app.timeline.evaluateJavaScript(func) - def logout(self, sender): print "logout is not implemented yet" @@ -301,35 +268,4 @@ class Console(QtCore.QObject): if __name__ == "__main__": - - key = 'BUNGLOO2' - - if len(sys.argv) > 1 and sys.argv[1] == "--help": - print """ -Usage: bungloo [option [text]] - -Options: ---new-message [text] Opens new message window with text ---search text Opens search with text - """ - sys.exit(1) - - if Helper.Helper.is_windows() and not Helper.Helper.is_local(): - import sys - from os import path, environ, makedirs - appdata = path.join(environ["TMP"], key) - if not path.exists(appdata): - makedirs(appdata) - sys.stdout = open(path.join(appdata, key + ".log"), "w") - sys.stderr = open(path.join(appdata, key + "_err.log"), "w") - - app = SingleApplication.SingleApplicationWithMessaging(sys.argv, key) - if app.isRunning(): - print json.dumps(sys.argv[1:]) - app.sendMessage(json.dumps(sys.argv[1:])) - sys.exit(1) - - app.bungloo = Bungloo() - app.connect(app, QtCore.SIGNAL('messageAvailable'), app.bungloo.handleMessage) - - sys.exit(app.exec_()) + Bungloo() diff --git a/Qt/Helper.py b/Linux/Helper.py similarity index 78% rename from Qt/Helper.py rename to Linux/Helper.py index d70b007..c822256 100644 --- a/Qt/Helper.py +++ b/Linux/Helper.py @@ -2,37 +2,17 @@ from PyQt4 import QtCore, QtGui, QtWebKit from PyQt4.QtCore import QTimer, QVariant, SIGNAL from PyQt4.QtGui import * -from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply, QSslSocket +from PyQt4.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply from PyQt4.QtWebKit import QWebView -from sys import platform as _platform -import os, sys, array +import os + +import array class Helper: - @classmethod - def get_resource_path(cls): - if Helper.is_windows(): - return os.path.dirname(sys.argv[0]) - elif Helper.is_mac(): - return os.path.dirname(sys.argv[0]) - else: - return os.path.dirname(__file__) - - @classmethod - def is_local(cls): - return os.path.basename(sys.argv[0]) == "Bungloo.py" - - @classmethod - def is_mac(cls): - return _platform == "darwin" - - @classmethod - def is_windows(cls): - return os.name == "nt" - - @classmethod - def is_linux(cls): - return not (Helper.is_windows() or Helper.is_mac()) + @classmethod + def get_resource_path(cls): + return os.path.dirname(__file__) class WebPage(QtWebKit.QWebPage): def __init__(self, parent=0, app=None): @@ -63,8 +43,6 @@ class WebViewCreator(QtWebKit.QWebView): self.customContextMenuRequested.connect(self.context_menu_requested) self.actions = [] - self.page().networkAccessManager().sslErrors.connect(lambda reply, errors: self.handleSslErrors(reply, errors)) - def copy_link(): self.page().triggerAction(QtWebKit.QWebPage.CopyLinkToClipboard) self.action_copy_link = QtGui.QAction('Copy Lin&k', self, triggered=copy_link) @@ -107,19 +85,14 @@ class WebViewCreator(QtWebKit.QWebView): def load_finished(self, ok, callback=None): frame = self.page().mainFrame() if self.is_local: - os_type = "linux" - if Helper.is_windows: - os_type = "windows" - elif Helper.is_mac: - os_type = "osx" - frame.evaluateJavaScript("var OS_TYPE = '" + os_type + "';") + frame.evaluateJavaScript("var OS_TYPE = 'linux';") - js_plugin_path = os.path.expanduser('~/.config/bungloo2/Plugin.js') + js_plugin_path = os.path.expanduser('~/.bungloo/Plugin.js') if os.access(js_plugin_path, os.R_OK): func = "setTimeout(function() { loadJsPlugin('file://localhost/" + js_plugin_path + "') }, 1000);" frame.evaluateJavaScript(func) - css_plugin_path = os.path.expanduser('~/.config/bungloo2/Plugin.css') + css_plugin_path = os.path.expanduser('~/.bungloo/Plugin.css') if os.access(css_plugin_path, os.R_OK): func = "setTimeout(function() { loadCssPlugin('file://localhost/" + css_plugin_path + "') }, 1000);" frame.evaluateJavaScript(func) @@ -127,12 +100,6 @@ class WebViewCreator(QtWebKit.QWebView): if callback: callback(ok) - def handleSslErrors(self, reply, errors): - if Helper.is_windows: # ignore SSL errors on Windows (yes a uggly workaround, don't know how to fix it yet) - for error in errors: - print error.errorString() - reply.ignoreSslErrors(errors) - class NetworkAccessManager(QNetworkAccessManager): @@ -146,7 +113,6 @@ class NetworkAccessManager(QNetworkAccessManager): self.setCookieJar(old_manager.cookieJar()) self.setProxy(old_manager.proxy()) self.setProxyFactory(old_manager.proxyFactory()) - self.sslErrors.connect(lambda reply, errors: old_manager.sslErrors) def createRequest(self, operation, request, data): if request.url().scheme() != "bungloo": diff --git a/Qt/Windows.py b/Linux/Windows.py similarity index 74% rename from Qt/Windows.py rename to Linux/Windows.py index d18e5ca..5fe85c3 100644 --- a/Qt/Windows.py +++ b/Linux/Windows.py @@ -1,5 +1,5 @@ from PyQt4 import QtCore, QtGui, QtWebKit -import Helper, urllib, urllib2, os +import Helper, urllib, urllib2 class Preferences: @@ -9,7 +9,7 @@ class Preferences: # window self.window = QtGui.QMainWindow() - self.window.setWindowTitle("Login") + self.window.setWindowTitle("Preferences") self.window.resize(480, 186) self.window.setMinimumSize(480, 186) self.window.setMaximumSize(480, 186) @@ -21,8 +21,7 @@ class Preferences: image_view.setPixmap(image) image_view.setScaledContents(True) - if not Helper.Helper.is_mac(): - self.window.setWindowIcon(QtGui.QIcon(image)) + self.window.setWindowIcon(QtGui.QIcon(image)) # info text info_text = QtGui.QLabel(self.window) @@ -77,17 +76,14 @@ class Preferences: class Timeline: - def __init__(self, app, action="timeline", title="Bungloo", custom_after_load=None): + def __init__(self, app, action="timeline", title="Bungloo"): self.app = app self.action = action self.title = title - self.custom_after_load = custom_after_load self.window = Helper.RestorableWindow(action, self.app) self.window.setWindowTitle(title) - - if not Helper.Helper.is_mac(): - self.window.setWindowIcon(QtGui.QIcon(self.app.resources_path() + "/images/Icon.png")) + self.window.setWindowIcon(QtGui.QIcon(self.app.resources_path() + "/images/Icon.png")) self.webView = Helper.WebViewCreator(self.app, True, self.window) self.webView.load_local(self.load_finished) @@ -117,11 +113,6 @@ class Timeline: findEntityAction.setStatusTip("Find entity and open its profile view") findEntityAction.triggered.connect(self.app.find_entity_show) - closeAction = QtGui.QAction("&Close Window", self.window) - closeAction.setShortcut("Ctrl+w") - closeAction.setStatusTip("Close this window") - closeAction.triggered.connect(self.window.close) - logOutAction = QtGui.QAction("&Log Out", self.window) logOutAction.setStatusTip("Log out from this entity") logOutAction.triggered.connect(self.app.log_out) @@ -134,7 +125,6 @@ class Timeline: fileMenu = menubar.addMenu("&File") fileMenu.addAction(newPostAction) fileMenu.addAction(findEntityAction) - fileMenu.addAction(closeAction) fileMenu.addSeparator() fileMenu.addAction(logOutAction) fileMenu.addAction(exitAction) @@ -164,19 +154,12 @@ class Timeline: searchAction.setStatusTip("Show Search") searchAction.triggered.connect(self.app.search_show) - nextAction = QtGui.QAction("&Next View", self.window) - nextAction.setShortcut("Ctrl+6") - nextAction.setStatusTip("Show Next") - nextAction.triggered.connect(self.app.next_show) - windowMenu = menubar.addMenu("&View") windowMenu.addAction(timelineAction) windowMenu.addAction(mentionsAction) windowMenu.addAction(conversationAction) windowMenu.addAction(profileAction) windowMenu.addAction(searchAction) - windowMenu.addSeparator() - windowMenu.addAction(nextAction) aboutAction = QtGui.QAction("&About Bungloo", self.window) aboutAction.setStatusTip("Open about page in Webbrowser") @@ -192,7 +175,8 @@ class Timeline: def show(self): self.window.show() - + #self.window.raise_() + #QtGui.qApp.setActiveWindow(self.window) def close(self): self.window.close() @@ -201,8 +185,6 @@ class Timeline: def load_finished(self, widget): script = "function HostAppGo() { start('" + self.action + "'); }" - if self.custom_after_load: - script = self.custom_after_load self.webView.page().mainFrame().evaluateJavaScript(script) def set_window_title(self, title): @@ -236,19 +218,14 @@ class Oauth: self.core.page().mainFrame().evaluateJavaScript(script) def handle_authentication(self, url): - self.app.controller.openURL(url) - return False - self.auth_view = Helper.WebViewCreator(self.app) self.auth_view.setWindowTitle("Authentication") old_manager = self.auth_view.page().networkAccessManager() new_manager = Helper.NetworkAccessManager(old_manager, self.bungloo_callback) new_manager.authenticationRequired.connect(self.authentication_required) - new_manager.sslErrors.connect(lambda reply, errors: self.handleSslErrors(reply, errors)) self.auth_view.page().setNetworkAccessManager(new_manager) self.auth_view.show() - self.auth_view.load_url(url) return False @@ -273,13 +250,6 @@ class Oauth: if hasattr(self, "auth_view"): self.auth_view.hide() - def handleSslErrors(self, reply, errors): - if os.name == "nt": # ignore SSL errors on Windows (yes a uggly workaround, don't know how to fix it yet) - for error in errors: - print error.errorString() - reply.ignoreSslErrors(errors) - - class Login(QtGui.QDialog): def __init__(self): @@ -335,30 +305,25 @@ class FindEntity(QtGui.QDialog): class NewPost(Helper.RestorableWindow): - def __init__(self, app, status_string): + def __init__(self, app): self.app = app - self.status_string = status_string - Helper.RestorableWindow.__init__(self, "newpost", self.app) - self.activateWindow() - self.raise_() - if not Helper.Helper.is_mac(): - self.setWindowIcon(QtGui.QIcon(self.app.resources_path() + "/images/Icon.png")) + self.setWindowIcon(QtGui.QIcon(self.app.resources_path() + "/images/Icon.png")) - self.webView = Helper.WebViewCreator(self.app, True, self) - self.webView.load_local(self.load_finished) - self.setCentralWidget(self.webView) - - self.initUI() - - self.webView.triggerPageAction(QtWebKit.QWebPage.InspectElement) - frame = self.webView.page().mainFrame() - frame.addToJavaScriptWindowObject("new_post_window", self) + self.textInput = QtGui.QPlainTextEdit(self) + self.setCentralWidget(self.textInput) + self.textInput.textChanged.connect(self.onChanged) self.setWindowTitle("New Post") self.resize(300, 150) self.setMinimumSize(100, 100) + self.initUI() + + self.setIsPrivate(False) + self.status_id = None + self.reply_to_entity = None + self.imageFilePath = None def initUI(self): newPostAction = QtGui.QAction("&New Post", self) @@ -407,38 +372,88 @@ class NewPost(Helper.RestorableWindow): aboutAction.setStatusTip("Open about page in Webbrowser") aboutAction.triggered.connect(self.app.open_about) - developerExtrasAction = QtGui.QAction("&Developer Extras", self) - developerExtrasAction.setStatusTip("Activate webkit inspector") - developerExtrasAction.triggered.connect(self.developer_extras) - helpMenu = menubar.addMenu("&Help") helpMenu.addAction(aboutAction) - helpMenu.addAction(developerExtrasAction) - def load_finished(self, widget): - callback = "function() { bungloo.newpost.setStatus(\"%s\"); }" % (self.status_string) - script = "function HostAppGo() { start('newpost', " + callback + "); }" - self.webView.page().mainFrame().evaluateJavaScript(script) - self.webView.setFocus() + + self.statusBar().showMessage('256') + + self.addButton = QtGui.QToolButton() + self.addButton.setToolTip("Add photo") + self.addButton.clicked.connect(self.openFileDialog) + self.addButton.setAutoRaise(True) + #addIcon = QtGui.QIcon.fromTheme("insert-image", QtGui.QIcon(self.app.resources_path() + "/images/Actions-insert-image-icon.png")) + addIcon = QtGui.QIcon(self.app.resources_path() + "/images/glyphicons_138_picture.png") + self.addButton.setIcon(addIcon) + self.statusBar().addPermanentWidget(self.addButton) + + self.isPrivateButton = QtGui.QToolButton() + self.isPrivateButton.setToolTip("Make private") + self.isPrivateButton.clicked.connect(self.toggleIsPrivate) + self.isPrivateButton.setAutoRaise(True) + #self.isPrivateIcon = QtGui.QIcon(self.app.resources_path() + "/images/Lock-Lock-icon.png") + self.isPrivateIcon = QtGui.QIcon(self.app.resources_path() + "/images/glyphicons_203_lock.png") + #self.isNotPrivateIcon = QtGui.QIcon(self.app.resources_path() + "/images/Lock-Unlock-icon.png") + self.isNotPrivateIcon = QtGui.QIcon(self.app.resources_path() + "/images/glyphicons_204_unlock.png") + self.isPrivateButton.setIcon(self.isNotPrivateIcon) + self.statusBar().addPermanentWidget(self.isPrivateButton) + + self.sendButton = QtGui.QToolButton() + self.sendButton.setToolTip("Send") + self.sendButton.clicked.connect(self.sendMessage) + self.sendButton.setAutoRaise(True) + #sendIcon = QtGui.QIcon.fromTheme("mail-send", QtGui.QIcon(self.app.resources_path() + "/images/send-icon.png")) + sendIcon = QtGui.QIcon(self.app.resources_path() + "/images/glyphicons_123_message_out.png") + self.sendButton.setIcon(sendIcon) + self.statusBar().addPermanentWidget(self.sendButton) + + def setIsPrivate(self, is_private): + self.isPrivate = is_private + icon = self.isNotPrivateIcon + if self.isPrivate: + icon = self.isPrivateIcon + + self.isPrivateButton.setIcon(icon) def toggleIsPrivate(self): - script = "bungloo.newpost.toggleIsPrivate();" - self.webView.page().mainFrame().evaluateJavaScript(script) + self.setIsPrivate(not self.isPrivate) + + def inReplyToStatusIdWithString(self, reply_to, status_id, string): + self.reply_to_entity = reply_to + self.status_id = status_id + self.textInput.setPlainText(string) + + cursor = self.textInput.textCursor() + cursor.movePosition(QtGui.QTextCursor.End, QtGui.QTextCursor.MoveAnchor) + cursor.movePosition(QtGui.QTextCursor.Start, QtGui.QTextCursor.KeepAnchor) + cursor.movePosition(QtGui.QTextCursor.EndOfLine, QtGui.QTextCursor.KeepAnchor) + self.textInput.setTextCursor(cursor) + + def onChanged(self): + count = 256 - len(self.textInput.toPlainText()) + self.statusBar().showMessage(str(count)) def sendMessage(self): - script = "bungloo.newpost.send()" - self.webView.page().mainFrame().evaluateJavaScript(script) - - def developer_extras(self, widget): - QtWebKit.QWebSettings.globalSettings().setAttribute(QtWebKit.QWebSettings.DeveloperExtrasEnabled, True) + count = len(self.textInput.toPlainText()) + if count > 0 and count <= 256: + message = Helper.PostModel() + message.text = unicode(self.textInput.toPlainText().toUtf8(), "utf-8") + message.inReplyTostatusId = self.status_id + message.inReplyToEntity = self.reply_to_entity + message.location = None + message.imageFilePath = self.imageFilePath + message.isPrivate = self.isPrivate + self.app.controller.sendMessage(message) + self.close() + else: + QtGui.qApp.beep() def openFileDialog(self): - print "openFileDialog Not implemented yet" + fileNamePath = QtGui.QFileDialog.getOpenFileName(self, "Choose a image", "", "Images (*.png *.gif *.jpg *.jpeg)") + if len(fileNamePath) > 0: + self.imageFilePath = str(fileNamePath) + else: + self.imageFilePath = None + - @QtCore.pyqtSlot() - def closeWindow(self): - self.close() - @QtCore.pyqtSlot() - def beep(self): - QtGui.qApp.beep() \ No newline at end of file diff --git a/Linux/bungloo.ebuild.exmp b/Linux/bungloo.ebuild.exmp deleted file mode 100644 index 4633edf..0000000 --- a/Linux/bungloo.ebuild.exmp +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 1999-2012 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 -# $Header: $ - -EAPI=5 -PYTHON_COMPAT=(python{2_6,2_7}) - -inherit eutils distutils-r1 - -DESCRIPTION="Qt4/KDE Tent client" -HOMEPAGE="https://jabs.nu/bungloo" - -LICENSE="BSD" -KEYWORDS="~x86 ~amd64" -SLOT="0" -IUSE="" -SRC_URI="http://jabs.nu/bungloo/download/${P}.tar.gz" - -DEPEND=">=dev-python/PyQt4-4.6" - diff --git a/Linux/debian/changelog b/Linux/debian/changelog deleted file mode 100644 index 5b66ff6..0000000 --- a/Linux/debian/changelog +++ /dev/null @@ -1,53 +0,0 @@ -bungloo (2.0.0) raring; urgency=high - - [Jeena Paradies] - * Nearly complete rewrite to be compatible with Tent 0.3 - - -- Jeena Paradies Tue, 09 Sep 2013 10:25:00 +0100 - -bungloo (1.4.3) raring; urgency=high - - [ Jeena Paradies ] - * bugfix with SingleApplication - - -- Jeena Paradies Tue, 28 Apr 2013 10:10:00 +0100 - -bungloo (1.4.2) raring; urgency=low - - [ Jeena Paradies ] - * Fixes the bug with wrongly showing uread mentions - * Added single application mode - * Added --new-message - * Added close window shortcut - * Bugfixes - - -- Jeena Paradies Tue, 28 Apr 2013 00:50:00 +0100 - -bungloo (1.4.0) quantal; urgency=low - - [ Jeena Paradies ] - * Added scroll to load more posts - * Added doubleclick for conversation in new window - * Added synchronized "read mentions" cursor - * Added "show next view" shortcut - * New possibilities for plugins - * Inverted "from" label position - * Bugfixes - - -- Jeena Paradies Tue, 17 Apr 2013 07:50:00 +0100 - -bungloo (1.3.0) quantal; urgency=low - - [ Jeena Paradies ] - * Changed to one window - * Added search (skate.io) - * Added log out - - -- Jeena Paradies Tue, 26 Mar 2013 21:50:00 +0100 - -bungloo (1.2.0) quantal; urgency=low - - [ Jeena Paradies ] - * Initial release. - - -- Jeena Paradies Tue, 05 Mar 2013 17:57:47 +0100 diff --git a/Linux/Makefile.exmp b/Linux/deploy/Makefile.exmp similarity index 93% rename from Linux/Makefile.exmp rename to Linux/deploy/Makefile.exmp index 5c35b0c..1e34feb 100644 --- a/Linux/Makefile.exmp +++ b/Linux/deploy/Makefile.exmp @@ -30,11 +30,9 @@ builddeb: rename -f 's/$(PROJECT)-(.*)\.tar\.gz/$(PROJECT)_$$1\.orig\.tar\.gz/' ../* # build the package dpkg-buildpackage -i -I -rfakeroot - dpkg-buildpackage -i -I -rfakeroot -S clean: $(PYTHON) setup.py clean $(MAKE) -f $(CURDIR)/debian/rules clean rm -rf build/ MANIFEST - find . -name '*.pyc' -delete - + find . -name '*.pyc' -delete \ No newline at end of file diff --git a/Linux/bungloo.desktop.exmp b/Linux/deploy/bungloo.desktop.exmp similarity index 66% rename from Linux/bungloo.desktop.exmp rename to Linux/deploy/bungloo.desktop.exmp index 84531c6..d21b077 100644 --- a/Linux/bungloo.desktop.exmp +++ b/Linux/deploy/bungloo.desktop.exmp @@ -1,13 +1,12 @@ [Desktop Entry] Version={VERSION} -Comment=Tent is a distributed social network protocol and Bungloo is one of the microbloging clients using it. -Exec=bungloo %U +Comment=Tent is a distributed social network protocol and Bungloo is one of the clients using it. +Exec=/usr/bin/bungloo GenericName=Tent Client -Icon=bungloo +Icon=/usr/share/pixmaps/bungloo.xpm Name=Bungloo NoDisplay=false StartupNotify=true Terminal=false Type=Application Categories=Network;Qt -MimeType=x-scheme-handler/bungloo; diff --git a/Linux/deploy/debian/changelog b/Linux/deploy/debian/changelog new file mode 100644 index 0000000..2ed9a7d --- /dev/null +++ b/Linux/deploy/debian/changelog @@ -0,0 +1,15 @@ +bungloo (2.0.0) quantal; urgency=low + + [ Jeena Paradies ] + * Changed to one window + * Added search (skate.io) + * Added log out + + -- Jeena Tue, 26 Mar 2013 21:50:00 +0100 + +bungloo (1.2.0) quantal; urgency=low + + [ Jeena Paradies ] + * Initial release. + + -- Jeena Tue, 05 Mar 2013 17:57:47 +0100 diff --git a/Linux/debian/compat b/Linux/deploy/debian/compat similarity index 100% rename from Linux/debian/compat rename to Linux/deploy/debian/compat diff --git a/Linux/debian/control b/Linux/deploy/debian/control similarity index 95% rename from Linux/debian/control rename to Linux/deploy/debian/control index 4f2e11c..15d7830 100644 --- a/Linux/debian/control +++ b/Linux/deploy/debian/control @@ -1,5 +1,5 @@ Source: bungloo -Section: net +Section: Miscellaneous Priority: optional Maintainer: Jeena Paradies Build-Depends: debhelper (>=7.0.50~), python-support (>= 0.6), cdbs (>= 0.4.49), python-all-dev diff --git a/Linux/debian/copyright b/Linux/deploy/debian/copyright similarity index 100% rename from Linux/debian/copyright rename to Linux/deploy/debian/copyright diff --git a/Linux/debian/rules b/Linux/deploy/debian/rules similarity index 99% rename from Linux/debian/rules rename to Linux/deploy/debian/rules index 351bb67..f0766df 100755 --- a/Linux/debian/rules +++ b/Linux/deploy/debian/rules @@ -15,4 +15,3 @@ install/bungloo:: clean:: rm -rf build build-stamp configure-stamp build/ MANIFEST dh_clean - diff --git a/Linux/deploy.sh b/Linux/deploy/deploy.sh similarity index 58% rename from Linux/deploy.sh rename to Linux/deploy/deploy.sh index 075e323..684e274 100755 --- a/Linux/deploy.sh +++ b/Linux/deploy/deploy.sh @@ -2,9 +2,9 @@ VERSION="2.0.0" DEPLOYPATH="bungloo-${VERSION}" -QTPATH="../Qt" -SHAREDPATH=".." -DISTPATH="dist" +LINUXPATH=".." +SHAREDPATH="../.." +DISTPATH=dist rm -rf $DEPLOYPATH rm -rf $DISTPATH @@ -14,8 +14,8 @@ mkdir -p $DEPLOYPATH/bin mkdir -p $DEPLOYPATH/bungloo touch $DEPLOYPATH/bungloo/__init__.py -cp $QTPATH/Bungloo.py $DEPLOYPATH/bin/bungloo -cp $QTPATH/Helper.py $QTPATH/Windows.py $QTPATH/SingleApplication.py $DEPLOYPATH/bungloo +cp $LINUXPATH/Bungloo.py $DEPLOYPATH/bin/bungloo +cp $LINUXPATH/Helper.py $LINUXPATH/Windows.py $DEPLOYPATH/bungloo cat setup.py.exmp | sed -e "s/{VERSION}/${VERSION}/g" > $DEPLOYPATH/setup.py cat Makefile.exmp | sed -e "s/{VERSION}/${VERSION}/g" > $DEPLOYPATH/Makefile cat bungloo.desktop.exmp | sed -e "s/{VERSION}/${VERSION}/g" > $DEPLOYPATH/bungloo.desktop @@ -24,6 +24,7 @@ cp -r $SHAREDPATH/images $DEPLOYPATH/bungloo/ cp $SHAREDPATH/readme.md $DEPLOYPATH/README cp $SHAREDPATH/LICENCE.txt $DEPLOYPATH/COPYING cp -r debian $DEPLOYPATH/ +cp bungloo.desktop $DEPLOYPATH/ cd $DEPLOYPATH make builddeb @@ -33,21 +34,16 @@ echo "Cleaning up ..." mv $DISTPATH .. cd .. - -cp bungloo.ebuild.exmp $DISTPATH/bungloo-${VERSION}.ebuild - mv bungloo_${VERSION}_all.deb $DISTPATH -mv bungloo_${VERSION}_amd64.changes $DISTPATH -mv bungloo_${VERSION}.diff.gz $DISTPATH -mv bungloo_${VERSION}.dsc $DISTPATH -mv bungloo_${VERSION}.orig.tar.gz $DISTPATH -mv bungloo_${VERSION}_source.changes $DISTPATH +rm bungloo_${VERSION}_amd64.changes +rm bungloo_${VERSION}.diff.gz +rm bungloo_${VERSION}.dsc +rm bungloo_${VERSION}.orig.tar.gz rm -rf $DEPLOYPATH rm $DISTPATH/bungloo-${VERSION}-1.src.rpm -mv $DISTPATH/bungloo-${VERSION}-1.noarch.rpm $DISTPATH/bungloo-${VERSION}.noarch.rpm echo "Done." -echo "dput ppa:jeena/bungloo $DISTPATH/bungloo_${VERSION}_source.changes" + # eof diff --git a/Linux/setup.py.exmp b/Linux/deploy/setup.py.exmp similarity index 78% rename from Linux/setup.py.exmp rename to Linux/deploy/setup.py.exmp index c9eaa8a..06130f5 100644 --- a/Linux/setup.py.exmp +++ b/Linux/deploy/setup.py.exmp @@ -21,9 +21,5 @@ setup( license = "BSD license", packages = ['bungloo'], package_data = {"bungloo": files}, - scripts = ["bin/bungloo"], - data_files=[ - ('/usr/share/applications', ["bungloo.desktop"]), - ('/usr/share/pixmaps', ["bungloo/images/bungloo.xpm"]) - ] -) + scripts = ["bin/bungloo"] + ) diff --git a/Mac/AccessToken.h b/Mac/AccessToken.h new file mode 100644 index 0000000..b9cbcf8 --- /dev/null +++ b/Mac/AccessToken.h @@ -0,0 +1,27 @@ +// +// AccessToken.h +// bungloo +// +// Created by Jeena Paradies on 19/09/2011. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + + + +@interface AccessToken : NSObject { + NSUserDefaults *d; +} + +- (void)setString:(NSString *)string forKey:(NSString *)aKey; +- (NSString *)stringForKey:(NSString *)aKey; + +- (void)setAccessToken:(NSString *)_accessToken; +- (NSString *)accessToken; +- (void)setSecret:(NSString *)_secret; +- (NSString *)secret; +- (void)setUserId:(NSString *)_userId; +- (NSString *)userId; +- (void)setScreenName:(NSString *)_screenName; +- (NSString *)screenName; + +@end \ No newline at end of file diff --git a/Mac/AccessToken.m b/Mac/AccessToken.m new file mode 100644 index 0000000..f60e91c --- /dev/null +++ b/Mac/AccessToken.m @@ -0,0 +1,130 @@ +// +// AccessToken.m +// bungloo +// +// Created by Jeena Paradies on 19/09/2011. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import "AccessToken.h" +#include + +@implementation AccessToken + +- (id)init +{ + self = [super init]; + if (self) { + // Initialization code here. + d = [NSUserDefaults standardUserDefaults]; + //[d removeObjectForKey:@"user_access_token"]; + } + + return self; +} + +- (void)setString:(NSString *)string forKey:(NSString *)aKey +{ + [d setObject:string forKey:aKey]; + [d synchronize]; +} + +- (NSString *)stringForKey:(NSString *)aKey +{ + return [d objectForKey:aKey]; +} + +- (void)setAccessToken:(NSString *)_accessToken +{ + [d synchronize]; +} + +- (NSString *)accessToken +{ + return [d objectForKey:@"accessToken"]; +} + +- (void)setSecret:(NSString *)_secret +{ + UInt32 _passwordLength = 0; + char *_password = nil; + SecKeychainItemRef item = nil; + SecKeychainFindGenericPassword(NULL, 6, "Bungloo", 17, "BunglooUserAccount", &_passwordLength, (void **)&_password, &item); + + OSStatus status; + void * passwordData = (void*)[_secret cStringUsingEncoding:NSUTF8StringEncoding]; + UInt32 passwordLength = strlen((char*)passwordData); + if (!item) + { + status = SecKeychainAddGenericPassword( + NULL, // default keychain + 6, // length of service name + "Bungloo", // service name + 17, // length of account name + "BunglooUserAccount", // account name + passwordLength, // length of password + passwordData, // pointer to password data + NULL // the item reference + ); + } + else + { + status = SecKeychainItemModifyContent( + item, + NULL, + passwordLength, + passwordData + ); + } + NSLog(@"%@",(NSString *)SecCopyErrorMessageString (status,NULL)); +} + +- (NSString *)secret +{ + UInt32 passwordLength = 0; + char *password = nil; + SecKeychainItemRef item = nil; + SecKeychainFindGenericPassword(NULL, 6, "Bungloo", 17, "BunglooUserAccount", &passwordLength, (void **)&password, &item); + + if (!item) { + return nil; + } + + //Get password + NSString *passwordString = [[[NSString alloc] initWithData:[NSData dataWithBytes:password length:passwordLength] encoding:NSUTF8StringEncoding] autorelease]; + SecKeychainItemFreeContent(NULL, password); + return passwordString; +} + +- (void)setUserId:(NSString *)_userId +{ + [d setObject:_userId forKey:@"userId"]; + [d synchronize]; +} + +- (NSString *)userId +{ + return [d objectForKey:@"userId"]; +} + +- (void)setScreenName:(NSString *)_screenName +{ + [d setObject:_screenName forKey:@"screenName"]; + [d synchronize]; +} + +- (NSString *)screenName +{ + return [d objectForKey:@"screenName"]; +} + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector { + return NO; +} + ++ (BOOL)isKeyExcludedFromWebScript:(const char *)name { + return NO; +} + + +@end diff --git a/Mac/Bungloo-Info.plist b/Mac/Bungloo-Info.plist new file mode 100644 index 0000000..87a0d8c --- /dev/null +++ b/Mac/Bungloo-Info.plist @@ -0,0 +1,80 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDocumentTypes + + + CFBundleTypeExtensions + + ???? + + CFBundleTypeIconFile + + CFBundleTypeName + DocumentType + CFBundleTypeOSTypes + + ???? + + CFBundleTypeRole + Editor + NSDocumentClass + NewMessageWindow + + + CFBundleExecutable + Bungloo + CFBundleHelpBookFolder + Bungloo.help + CFBundleHelpBookName + nu.jabs.apps.bungloo.help + CFBundleIconFile + Icon.icns + CFBundleIdentifier + nu.jabs.apps.bungloo + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Bungloo + CFBundlePackageType + APPL + CFBundleShortVersionString + 2.0.0 + CFBundleSignature + ???? + CFBundleURLTypes + + + CFBundleURLName + nu.jabs.apps.bungloo.handler + CFBundleURLSchemes + + bungloo + + + + CFBundleVersion + 2.0.0 + LSApplicationCategoryType + public.app-category.social-networking + LSMinimumSystemVersion + ${MACOSX_DEPLOYMENT_TARGET} + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + NSServices + + SUFeedURL + http://jabs.nu/bungloo/download/Appcast.xml + SUPublicDSAKeyFile + dsa_pub.pem + UTExportedTypeDeclarations + + UTImportedTypeDeclarations + + + diff --git a/Mac/Bungloo.temp_caseinsensitive_rename_Prefix.pch b/Mac/Bungloo.temp_caseinsensitive_rename_Prefix.pch new file mode 100644 index 0000000..694af35 --- /dev/null +++ b/Mac/Bungloo.temp_caseinsensitive_rename_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'bungloo' target in the 'bungloo' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/Mac/Bungloo.xcodeproj/jeena.mode1v3 b/Mac/Bungloo.xcodeproj/jeena.mode1v3 new file mode 100644 index 0000000..777a537 --- /dev/null +++ b/Mac/Bungloo.xcodeproj/jeena.mode1v3 @@ -0,0 +1,1421 @@ + + + + + ActivePerspectiveName + Project + AllowedModules + + + BundleLoadPath + + MaxInstances + n + Module + PBXSmartGroupTreeModule + Name + Groups and Files Outline View + + + BundleLoadPath + + MaxInstances + n + Module + PBXNavigatorGroup + Name + Editor + + + BundleLoadPath + + MaxInstances + n + Module + XCTaskListModule + Name + Task List + + + BundleLoadPath + + MaxInstances + n + Module + XCDetailModule + Name + File and Smart Group Detail Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXBuildResultsModule + Name + Detailed Build Results Viewer + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXProjectFindModule + Name + Project Batch Find Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCProjectFormatConflictsModule + Name + Project Format Conflicts List + + + BundleLoadPath + + MaxInstances + n + Module + PBXBookmarksModule + Name + Bookmarks Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXClassBrowserModule + Name + Class Browser + + + BundleLoadPath + + MaxInstances + n + Module + PBXCVSModule + Name + Source Code Control Tool + + + BundleLoadPath + + MaxInstances + n + Module + PBXDebugBreakpointsModule + Name + Debug Breakpoints Tool + + + BundleLoadPath + + MaxInstances + n + Module + XCDockableInspector + Name + Inspector + + + BundleLoadPath + + MaxInstances + n + Module + PBXOpenQuicklyModule + Name + Open Quickly Tool + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugSessionModule + Name + Debugger + + + BundleLoadPath + + MaxInstances + 1 + Module + PBXDebugCLIModule + Name + Debug Console + + + BundleLoadPath + + MaxInstances + n + Module + XCSnapshotModule + Name + Snapshots Tool + + + BundlePath + /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources + Description + DefaultDescriptionKey + DockingSystemVisible + + Extension + mode1v3 + FavBarConfig + + PBXProjectModuleGUID + 1F68211F1249D25900A03CED + XCBarModuleItemNames + + XCBarModuleItems + + + FirstTimeWindowDisplayed + + Identifier + com.apple.perspectives.project.mode1v3 + MajorVersion + 33 + MinorVersion + 0 + Name + Default + Notifications + + OpenEditors + + PerspectiveWidths + + -1 + -1 + + Perspectives + + + ChosenToolbarItems + + active-combo-popup + action + NSToolbarFlexibleSpaceItem + build-and-go + com.apple.ide.PBXToolbarStopButton + get-info + NSToolbarFlexibleSpaceItem + com.apple.pbx.toolbar.searchfield + + ControllerClassBaseName + + IconName + WindowOfProjectWithEditor + Identifier + perspective.project + IsVertical + + Layout + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 287 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 2A37F4AAFDCFA73011CA2CEA + 2A37F4ABFDCFA73011CA2CEA + 2A37F4B8FDCFA73011CA2CEA + 1FFA36C71177D861006C8562 + 2A37F4C3FDCFA73011CA2CEA + 1058C7A6FEA54F5311CA2CBB + 1C37FAAC04509CD000000102 + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 37 + 17 + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {287, 1304}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {304, 1322}} + GroupTreeTableConfiguration + + MainColumn + 287 + + RubberWindowFrame + 469 55 1319 1363 0 0 2560 1418 + + Module + PBXSmartGroupTreeModule + Proportion + 304pt + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20306471E060097A5F4 + PBXProjectModuleLabel + TwittiaCore.js + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CE0B20406471E060097A5F4 + PBXProjectModuleLabel + TwittiaCore.js + _historyCapacity + 0 + bookmark + 1F8D1E4412DF5A0D00571730 + history + + 1F98DCA9124C691A004289ED + 1F98DCAD124C691A004289ED + 1F17508512A972DF004A0B42 + 1F2F793712BD93A600F073BE + 1F27470412D905CA00339B4F + 1F618EAC12DB5D0700E500D9 + 1F618ED112DB60D100E500D9 + 1F618ED212DB60D100E500D9 + 1F618ED312DB60D100E500D9 + 1F618ED412DB60D100E500D9 + 1F618ED512DB60D100E500D9 + 1F618ED612DB60D100E500D9 + 1F618F0212DB665B00E500D9 + 1F618F0312DB665B00E500D9 + 1F618F0412DB665B00E500D9 + 1F618F0512DB665B00E500D9 + 1F8D1E4212DF5A0D00571730 + 1F8D1E4312DF5A0D00571730 + + + SplitCount + 1 + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {1010, 1317}} + RubberWindowFrame + 469 55 1319 1363 0 0 2560 1418 + + Module + PBXNavigatorGroup + Proportion + 1317pt + + + ContentConfiguration + + PBXProjectModuleGUID + 1CE0B20506471E060097A5F4 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{0, 1322}, {1010, 0}} + RubberWindowFrame + 469 55 1319 1363 0 0 2560 1418 + + Module + XCDetailModule + Proportion + 0pt + + + Proportion + 1010pt + + + Name + Project + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + XCModuleDock + PBXNavigatorGroup + XCDetailModule + + TableOfContents + + 1F8D1E2712DF55D600571730 + 1CE0B1FE06471DED0097A5F4 + 1F8D1E2812DF55D600571730 + 1CE0B20306471E060097A5F4 + 1CE0B20506471E060097A5F4 + + ToolbarConfigUserDefaultsMinorVersion + 2 + ToolbarConfiguration + xcode.toolbar.config.defaultV3 + + + ControllerClassBaseName + + IconName + WindowOfProject + Identifier + perspective.morph + IsVertical + 0 + Layout + + + BecomeActive + 1 + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C37FBAC04509CD000000102 + 1C37FAAC04509CD000000102 + 1C08E77C0454961000C914BD + 1C37FABC05509CD000000102 + 1C37FABC05539CD112110102 + E2644B35053B69B200211256 + 1C37FABC04509CD000100104 + 1CC0EA4004350EF90044410B + 1CC0EA4004350EF90041110B + + PBXProjectModuleGUID + 11E0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + yes + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 186 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 29B97314FDCFA39411CA2CEA + 1C37FABC05509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {186, 337}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + 1 + XCSharingToken + com.apple.Xcode.GFSharingToken + + GeometryConfiguration + + Frame + {{0, 0}, {203, 355}} + GroupTreeTableConfiguration + + MainColumn + 186 + + RubberWindowFrame + 373 269 690 397 0 0 1440 878 + + Module + PBXSmartGroupTreeModule + Proportion + 100% + + + Name + Morph + PreferredWidth + 300 + ServiceClasses + + XCModuleDock + PBXSmartGroupTreeModule + + TableOfContents + + 11E0B1FE06471DED0097A5F4 + + ToolbarConfiguration + xcode.toolbar.config.default.shortV3 + + + PerspectivesBarVisible + + ShelfIsVisible + + SourceDescription + file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec' + StatusbarIsVisible + + TimeStamp + 0.0 + ToolbarConfigUserDefaultsMinorVersion + 2 + ToolbarDisplayMode + 1 + ToolbarIsVisible + + ToolbarSizeMode + 1 + Type + Perspectives + UpdateMessage + The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'? + WindowJustification + 5 + WindowOrderList + + 1F8D1E4612DF5A0D00571730 + 1F8D1E4712DF5A0D00571730 + 1F6821201249D25900A03CED + 1CD10A99069EF8BA00B06720 + 1C78EAAD065D492600B07095 + /Users/jeena/Projects/Twittia/Twittia 2.xcodeproj + + WindowString + 469 55 1319 1363 0 0 2560 1418 + WindowToolsV3 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.build + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528F0623707200166675 + PBXProjectModuleLabel + + StatusBarVisibility + + + GeometryConfiguration + + Frame + {{0, 0}, {1299, 402}} + RubberWindowFrame + 2771 56 1299 684 2560 0 1920 1200 + + Module + PBXNavigatorGroup + Proportion + 402pt + + + ContentConfiguration + + PBXProjectModuleGUID + XCMainBuildResultsModuleGUID + PBXProjectModuleLabel + Build Results + XCBuildResultsTrigger_Collapse + 1021 + XCBuildResultsTrigger_Open + 1011 + + GeometryConfiguration + + Frame + {{0, 407}, {1299, 236}} + RubberWindowFrame + 2771 56 1299 684 2560 0 1920 1200 + + Module + PBXBuildResultsModule + Proportion + 236pt + + + Proportion + 643pt + + + Name + Build Results + ServiceClasses + + PBXBuildResultsModule + + StatusbarIsVisible + + TableOfContents + + 1F6821201249D25900A03CED + 1F8D1E2912DF55D600571730 + 1CD0528F0623707200166675 + XCMainBuildResultsModuleGUID + + ToolbarConfiguration + xcode.toolbar.config.buildV3 + WindowContentMinSize + 486 300 + WindowString + 2771 56 1299 684 2560 0 1920 1200 + WindowToolGUID + 1F6821201249D25900A03CED + WindowToolIsVisible + + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debugger + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + Debugger + + HorizontalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {316, 203}} + {{316, 0}, {378, 203}} + + + VerticalSplitView + + _collapsingFrameDimension + 0.0 + _indexOfCollapsedView + 0 + _percentageOfCollapsedView + 0.0 + isCollapsed + yes + sizes + + {{0, 0}, {694, 203}} + {{0, 203}, {694, 178}} + + + + LauncherConfigVersion + 8 + PBXProjectModuleGUID + 1C162984064C10D400B95A72 + PBXProjectModuleLabel + Debug - GLUTExamples (Underwater) + + GeometryConfiguration + + DebugConsoleVisible + None + DebugConsoleWindowFrame + {{200, 200}, {500, 300}} + DebugSTDIOWindowFrame + {{200, 200}, {500, 300}} + Frame + {{0, 0}, {694, 381}} + PBXDebugSessionStackFrameViewKey + + DebugVariablesTableConfiguration + + Name + 120 + Value + 85 + Summary + 148 + + Frame + {{316, 0}, {378, 203}} + RubberWindowFrame + 67 996 694 422 0 0 2560 1418 + + RubberWindowFrame + 67 996 694 422 0 0 2560 1418 + + Module + PBXDebugSessionModule + Proportion + 381pt + + + Proportion + 381pt + + + Name + Debugger + ServiceClasses + + PBXDebugSessionModule + + StatusbarIsVisible + + TableOfContents + + 1CD10A99069EF8BA00B06720 + 1F8D1E2A12DF55D600571730 + 1C162984064C10D400B95A72 + 1F8D1E2B12DF55D600571730 + 1F8D1E2C12DF55D600571730 + 1F8D1E2D12DF55D600571730 + 1F8D1E2E12DF55D600571730 + 1F8D1E2F12DF55D600571730 + + ToolbarConfiguration + xcode.toolbar.config.debugV3 + WindowString + 67 996 694 422 0 0 2560 1418 + WindowToolGUID + 1CD10A99069EF8BA00B06720 + WindowToolIsVisible + + + + Identifier + windowTool.find + Layout + + + Dock + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1CDD528C0622207200134675 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1CD0528D0623707200166675 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {781, 167}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXNavigatorGroup + Proportion + 781pt + + + Proportion + 50% + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD0528E0623707200166675 + PBXProjectModuleLabel + Project Find + + GeometryConfiguration + + Frame + {{8, 0}, {773, 254}} + RubberWindowFrame + 62 385 781 470 0 0 1440 878 + + Module + PBXProjectFindModule + Proportion + 50% + + + Proportion + 428pt + + + Name + Project Find + ServiceClasses + + PBXProjectFindModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C530D57069F1CE1000CFCEE + 1C530D58069F1CE1000CFCEE + 1C530D59069F1CE1000CFCEE + 1CDD528C0622207200134675 + 1C530D5A069F1CE1000CFCEE + 1CE0B1FE06471DED0097A5F4 + 1CD0528E0623707200166675 + + WindowString + 62 385 781 470 0 0 1440 878 + WindowToolGUID + 1C530D57069F1CE1000CFCEE + WindowToolIsVisible + 0 + + + Identifier + MENUSEPARATOR + + + FirstTimeWindowDisplayed + + Identifier + windowTool.debuggerConsole + IsVertical + + Layout + + + Dock + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAAC065D492600B07095 + PBXProjectModuleLabel + Debugger Console + + GeometryConfiguration + + Frame + {{0, 0}, {968, 946}} + RubberWindowFrame + 2810 187 968 987 2560 0 1920 1200 + + Module + PBXDebugCLIModule + Proportion + 946pt + + + Proportion + 946pt + + + Name + Debugger Console + ServiceClasses + + PBXDebugCLIModule + + StatusbarIsVisible + + TableOfContents + + 1C78EAAD065D492600B07095 + 1F8D1E4512DF5A0D00571730 + 1C78EAAC065D492600B07095 + + ToolbarConfiguration + xcode.toolbar.config.consoleV3 + WindowString + 2810 187 968 987 2560 0 1920 1200 + WindowToolGUID + 1C78EAAD065D492600B07095 + WindowToolIsVisible + + + + Identifier + windowTool.snapshots + Layout + + + Dock + + + Module + XCSnapshotModule + Proportion + 100% + + + Proportion + 100% + + + Name + Snapshots + ServiceClasses + + XCSnapshotModule + + StatusbarIsVisible + Yes + ToolbarConfiguration + xcode.toolbar.config.snapshots + WindowString + 315 824 300 550 0 0 1440 878 + WindowToolIsVisible + Yes + + + Identifier + windowTool.scm + Layout + + + Dock + + + ContentConfiguration + + PBXProjectModuleGUID + 1C78EAB2065D492600B07095 + PBXProjectModuleLabel + <No Editor> + PBXSplitModuleInNavigatorKey + + Split0 + + PBXProjectModuleGUID + 1C78EAB3065D492600B07095 + + SplitCount + 1 + + StatusBarVisibility + 1 + + GeometryConfiguration + + Frame + {{0, 0}, {452, 0}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + + Module + PBXNavigatorGroup + Proportion + 0pt + + + BecomeActive + 1 + ContentConfiguration + + PBXProjectModuleGUID + 1CD052920623707200166675 + PBXProjectModuleLabel + SCM + + GeometryConfiguration + + ConsoleFrame + {{0, 259}, {452, 0}} + Frame + {{0, 7}, {452, 259}} + RubberWindowFrame + 743 379 452 308 0 0 1280 1002 + TableConfiguration + + Status + 30 + FileName + 199 + Path + 197.0950012207031 + + TableFrame + {{0, 0}, {452, 250}} + + Module + PBXCVSModule + Proportion + 262pt + + + Proportion + 266pt + + + Name + SCM + ServiceClasses + + PBXCVSModule + + StatusbarIsVisible + 1 + TableOfContents + + 1C78EAB4065D492600B07095 + 1C78EAB5065D492600B07095 + 1C78EAB2065D492600B07095 + 1CD052920623707200166675 + + ToolbarConfiguration + xcode.toolbar.config.scm + WindowString + 743 379 452 308 0 0 1280 1002 + + + FirstTimeWindowDisplayed + + Identifier + windowTool.breakpoints + IsVertical + + Layout + + + Dock + + + ContentConfiguration + + PBXBottomSmartGroupGIDs + + 1C77FABC04509CD000000102 + + PBXProjectModuleGUID + 1CE0B1FE06471DED0097A5F4 + PBXProjectModuleLabel + Files + PBXProjectStructureProvided + no + PBXSmartGroupTreeModuleColumnData + + PBXSmartGroupTreeModuleColumnWidthsKey + + 168 + + PBXSmartGroupTreeModuleColumnsKey_v4 + + MainColumn + + + PBXSmartGroupTreeModuleOutlineStateKey_v7 + + PBXSmartGroupTreeModuleOutlineStateExpansionKey + + 1C77FABC04509CD000000102 + + PBXSmartGroupTreeModuleOutlineStateSelectionKey + + + 0 + + + PBXSmartGroupTreeModuleOutlineStateVisibleRectKey + {{0, 0}, {168, 350}} + + PBXTopSmartGroupGIDs + + XCIncludePerspectivesSwitch + + + GeometryConfiguration + + Frame + {{0, 0}, {185, 368}} + GroupTreeTableConfiguration + + MainColumn + 168 + + RubberWindowFrame + 836 546 744 409 0 0 2560 1418 + + Module + PBXSmartGroupTreeModule + Proportion + 185pt + + + BecomeActive + + ContentConfiguration + + PBXProjectModuleGUID + 1CA1AED706398EBD00589147 + PBXProjectModuleLabel + Detail + + GeometryConfiguration + + Frame + {{190, 0}, {554, 368}} + RubberWindowFrame + 836 546 744 409 0 0 2560 1418 + + Module + XCDetailModule + Proportion + 554pt + + + Proportion + 368pt + + + MajorVersion + 3 + MinorVersion + 0 + Name + Breakpoints + ServiceClasses + + PBXSmartGroupTreeModule + XCDetailModule + + StatusbarIsVisible + + TableOfContents + + 1F618EB812DB5D0700E500D9 + 1F618EB912DB5D0700E500D9 + 1CE0B1FE06471DED0097A5F4 + 1CA1AED706398EBD00589147 + + ToolbarConfiguration + xcode.toolbar.config.breakpointsV3 + WindowString + 836 546 744 409 0 0 2560 1418 + WindowToolGUID + 1F618EB812DB5D0700E500D9 + WindowToolIsVisible + + + + Identifier + windowTool.debugAnimator + Layout + + + Dock + + + Module + PBXNavigatorGroup + Proportion + 100% + + + Proportion + 100% + + + Name + Debug Visualizer + ServiceClasses + + PBXNavigatorGroup + + StatusbarIsVisible + 1 + ToolbarConfiguration + xcode.toolbar.config.debugAnimatorV3 + WindowString + 100 100 700 500 0 0 1280 1002 + + + Identifier + windowTool.bookmarks + Layout + + + Dock + + + Module + PBXBookmarksModule + Proportion + 100% + + + Proportion + 100% + + + Name + Bookmarks + ServiceClasses + + PBXBookmarksModule + + StatusbarIsVisible + 0 + WindowString + 538 42 401 187 0 0 1280 1002 + + + Identifier + windowTool.projectFormatConflicts + Layout + + + Dock + + + Module + XCProjectFormatConflictsModule + Proportion + 100% + + + Proportion + 100% + + + Name + Project Format Conflicts + ServiceClasses + + XCProjectFormatConflictsModule + + StatusbarIsVisible + 0 + WindowContentMinSize + 450 300 + WindowString + 50 850 472 307 0 0 1440 877 + + + Identifier + windowTool.classBrowser + Layout + + + Dock + + + BecomeActive + 1 + ContentConfiguration + + OptionsSetName + Hierarchy, all classes + PBXProjectModuleGUID + 1CA6456E063B45B4001379D8 + PBXProjectModuleLabel + Class Browser - NSObject + + GeometryConfiguration + + ClassesFrame + {{0, 0}, {374, 96}} + ClassesTreeTableConfiguration + + PBXClassNameColumnIdentifier + 208 + PBXClassBookColumnIdentifier + 22 + + Frame + {{0, 0}, {630, 331}} + MembersFrame + {{0, 105}, {374, 395}} + MembersTreeTableConfiguration + + PBXMemberTypeIconColumnIdentifier + 22 + PBXMemberNameColumnIdentifier + 216 + PBXMemberTypeColumnIdentifier + 97 + PBXMemberBookColumnIdentifier + 22 + + PBXModuleWindowStatusBarHidden2 + 1 + RubberWindowFrame + 385 179 630 352 0 0 1440 878 + + Module + PBXClassBrowserModule + Proportion + 332pt + + + Proportion + 332pt + + + Name + Class Browser + ServiceClasses + + PBXClassBrowserModule + + StatusbarIsVisible + 0 + TableOfContents + + 1C0AD2AF069F1E9B00FABCE6 + 1C0AD2B0069F1E9B00FABCE6 + 1CA6456E063B45B4001379D8 + + ToolbarConfiguration + xcode.toolbar.config.classbrowser + WindowString + 385 179 630 352 0 0 1440 878 + WindowToolGUID + 1C0AD2AF069F1E9B00FABCE6 + WindowToolIsVisible + 0 + + + Identifier + windowTool.refactoring + IncludeInToolsMenu + 0 + Layout + + + Dock + + + BecomeActive + 1 + GeometryConfiguration + + Frame + {0, 0}, {500, 335} + RubberWindowFrame + {0, 0}, {500, 335} + + Module + XCRefactoringModule + Proportion + 100% + + + Proportion + 100% + + + Name + Refactoring + ServiceClasses + + XCRefactoringModule + + WindowString + 200 200 500 356 0 0 1920 1200 + + + + diff --git a/Mac/Bungloo.xcodeproj/jeena.pbxuser b/Mac/Bungloo.xcodeproj/jeena.pbxuser new file mode 100644 index 0000000..16fe5ce --- /dev/null +++ b/Mac/Bungloo.xcodeproj/jeena.pbxuser @@ -0,0 +1,496 @@ +// !$*UTF8*$! +{ + 1F17508512A972DF004A0B42 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1FFA36CB1177D861006C8562 /* default.css */; + name = "default.css: 80"; + rLen = 0; + rLoc = 1037; + rType = 0; + vrLen = 553; + vrLoc = 411; + }; + 1F198FC7117BC4AB0049BEA7 /* README.markdown */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {949, 1237}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1498}"; + }; + }; + 1F1990DF117BD2250049BEA7 /* Appcast.xml */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {949, 1237}}"; + sepNavSelRange = "{784, 0}"; + sepNavVisRange = "{0, 954}"; + }; + }; + 1F1990E1117BD2650049BEA7 /* ReleaseNotes.html */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {949, 1285}}"; + sepNavSelRange = "{461, 0}"; + sepNavVisRange = "{0, 1964}"; + }; + }; + 1F27470412D905CA00339B4F /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1FE2FCA6117A8952000504B0 /* dsa_pub.pem */; + name = "dsa_pub.pem: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1178; + vrLoc = 0; + }; + 1F2F793712BD93A600F073BE /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1FFA36D51177D879006C8562 /* ViewDelegate.m */; + name = "ViewDelegate.m: 37"; + rLen = 13; + rLoc = 1089; + rType = 0; + vrLen = 1550; + vrLoc = 0; + }; + 1F364396118CBC77008198EF /* OAuth.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {949, 1237}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 636}"; + }; + }; + 1F364397118CBC77008198EF /* OAuth.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1034, 2655}}"; + sepNavSelRange = "{4216, 0}"; + sepNavVisRange = "{2668, 3057}"; + }; + }; + 1F4673E61180F654006CC37C /* TwittiaCore.js */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1013, 5355}}"; + sepNavSelRange = "{1631, 0}"; + sepNavVisRange = "{248, 3030}"; + }; + }; + 1F618EA612DB5D0200E500D9 /* MyDocument.m:108 */ = { + isa = PBXFileBreakpoint; + actions = ( + ); + breakpointStyle = 0; + continueAfterActions = 0; + countType = 0; + delayBeforeContinue = 0; + fileReference = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.m */; + functionName = "-sendTweet:"; + hitCount = 1; + ignoreCount = 0; + lineNumber = 108; + location = Twittia; + modificationTime = 316627463.947617; + originalNumberOfMultipleMatches = 1; + state = 1; + }; + 1F618EAC12DB5D0700E500D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; + name = "MyDocument.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 573; + vrLoc = 0; + }; + 1F618EC812DB5E6100E500D9 /* TweetModel.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {949, 1262}}"; + sepNavSelRange = "{358, 0}"; + sepNavVisRange = "{0, 366}"; + }; + }; + 1F618EC912DB5E6100E500D9 /* TweetModel.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {949, 1262}}"; + sepNavSelRange = "{279, 0}"; + sepNavVisRange = "{0, 316}"; + }; + }; + 1F618ED112DB60D100E500D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.m */; + name = "MyDocument.m: 107"; + rLen = 0; + rLoc = 3758; + rType = 0; + vrLen = 3377; + vrLoc = 537; + }; + 1F618ED212DB60D100E500D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1F618EC812DB5E6100E500D9 /* TweetModel.h */; + name = "TweetModel.h: 18"; + rLen = 0; + rLoc = 358; + rType = 0; + vrLen = 366; + vrLoc = 0; + }; + 1F618ED312DB60D100E500D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1F618EC912DB5E6100E500D9 /* TweetModel.m */; + name = "TweetModel.m: 18"; + rLen = 0; + rLoc = 279; + rType = 0; + vrLen = 316; + vrLoc = 0; + }; + 1F618ED412DB60D100E500D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1FFA36D21177D879006C8562 /* Controller.h */; + name = "Controller.h: 10"; + rLen = 25; + rLoc = 149; + rType = 0; + vrLen = 1539; + vrLoc = 0; + }; + 1F618ED512DB60D100E500D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1F364396118CBC77008198EF /* OAuth.h */; + name = "OAuth.h: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 636; + vrLoc = 0; + }; + 1F618ED612DB60D100E500D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1F364397118CBC77008198EF /* OAuth.m */; + name = "OAuth.m: 135"; + rLen = 0; + rLoc = 4216; + rType = 0; + vrLen = 3057; + vrLoc = 2668; + }; + 1F618F0212DB665B00E500D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1FFA36D31177D879006C8562 /* Controller.m */; + name = "Controller.m: 178"; + rLen = 0; + rLoc = 5952; + rType = 0; + vrLen = 2979; + vrLoc = 4466; + }; + 1F618F0312DB665B00E500D9 /* PlistBookmark */ = { + isa = PlistBookmark; + fRef = 8D15AC360486D014006FF6A4 /* Twittia_2-Info.plist */; + fallbackIsa = PBXBookmark; + isK = 0; + kPath = ( + LSMinimumSystemVersion, + ); + name = "/Users/jeena/Projects/Twittia/Twittia_2-Info.plist"; + rLen = 0; + rLoc = 9223372036854775808; + }; + 1F618F0412DB665B00E500D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1F1990DF117BD2250049BEA7 /* Appcast.xml */; + name = "Appcast.xml: 15"; + rLen = 0; + rLoc = 784; + rType = 0; + vrLen = 954; + vrLoc = 0; + }; + 1F618F0512DB665B00E500D9 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1F198FC7117BC4AB0049BEA7 /* README.markdown */; + name = "README.markdown: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1498; + vrLoc = 0; + }; + 1F68210012493A3400A03CED /* Twittia */ = { + isa = PBXExecutable; + activeArgIndices = ( + ); + argumentStrings = ( + ); + autoAttachOnCrash = 1; + breakpointsEnabled = 0; + configStateDict = { + }; + customDataFormattersEnabled = 1; + dataTipCustomDataFormattersEnabled = 1; + dataTipShowTypeColumn = 1; + dataTipSortType = 0; + debuggerPlugin = GDBDebugging; + disassemblyDisplayState = 0; + dylibVariantSuffix = ""; + enableDebugStr = 1; + environmentEntries = ( + ); + executableSystemSymbolLevel = 0; + executableUserSymbolLevel = 0; + libgmallocEnabled = 0; + name = Twittia; + savedGlobals = { + }; + showTypeColumn = 0; + sourceDirectories = ( + ); + variableFormatDictionary = { + }; + }; + 1F68211B12493A5400A03CED /* Source Control */ = { + isa = PBXSourceControlManager; + fallbackIsa = XCSourceControlManager; + isSCMEnabled = 0; + scmConfiguration = { + repositoryNamesForRoots = { + "" = ""; + }; + }; + }; + 1F68211C12493A5400A03CED /* Code sense */ = { + isa = PBXCodeSenseManager; + indexTemplatePath = ""; + }; + 1F77DB46118C5F1C007C7F1E /* Constants.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1115, 3300}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1114}"; + }; + }; + 1F8D1E4212DF5A0D00571730 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1F1990E1117BD2650049BEA7 /* ReleaseNotes.html */; + name = "ReleaseNotes.html: 16"; + rLen = 0; + rLoc = 461; + rType = 0; + vrLen = 1964; + vrLoc = 0; + }; + 1F8D1E4312DF5A0D00571730 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1F4673E61180F654006CC37C /* TwittiaCore.js */; + name = "TwittiaCore.js: 90"; + rLen = 3; + rLoc = 3369; + rType = 0; + vrLen = 3174; + vrLoc = 376; + }; + 1F8D1E4412DF5A0D00571730 /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1F4673E61180F654006CC37C /* TwittiaCore.js */; + name = "TwittiaCore.js: 66"; + rLen = 0; + rLoc = 1631; + rType = 0; + vrLen = 3030; + vrLoc = 248; + }; + 1F98DCA9124C691A004289ED /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 1F77DB46118C5F1C007C7F1E /* Constants.m */; + name = "Constants.m: 1"; + rLen = 0; + rLoc = 0; + rType = 0; + vrLen = 1114; + vrLoc = 0; + }; + 1F98DCAD124C691A004289ED /* PBXBookmark */ = { + isa = PBXBookmark; + fRef = 1F98DC9D124BFFD7004289ED /* pin.png */; + }; + 1FE2FCA6117A8952000504B0 /* dsa_pub.pem */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {949, 865}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 1178}"; + }; + }; + 1FFA36CB1177D861006C8562 /* default.css */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1115, 3270}}"; + sepNavSelRange = "{1037, 0}"; + sepNavVisRange = "{411, 553}"; + }; + }; + 1FFA36D21177D879006C8562 /* Controller.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {949, 1237}}"; + sepNavSelRange = "{149, 25}"; + sepNavVisRange = "{0, 1539}"; + }; + }; + 1FFA36D31177D879006C8562 /* Controller.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1238, 3285}}"; + sepNavSelRange = "{5834, 0}"; + sepNavVisRange = "{5432, 1211}"; + }; + }; + 1FFA36D51177D879006C8562 /* ViewDelegate.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1517, 1237}}"; + sepNavSelRange = "{1089, 13}"; + sepNavVisRange = "{0, 1550}"; + }; + }; + 2A37F4A9FDCFA73011CA2CEA /* Project object */ = { + activeBuildConfigurationName = Release; + activeExecutable = 1F68210012493A3400A03CED /* Twittia */; + activeTarget = 8D15AC270486D014006FF6A4 /* Twittia */; + addToTargets = ( + 8D15AC270486D014006FF6A4 /* Twittia */, + ); + breakpoints = ( + 1F618EA612DB5D0200E500D9 /* MyDocument.m:108 */, + ); + codeSenseManager = 1F68211C12493A5400A03CED /* Code sense */; + executables = ( + 1F68210012493A3400A03CED /* Twittia */, + ); + perUserDictionary = { + "PBXConfiguration.PBXBreakpointsDataSource.v1:1CA1AED706398EBD00589147" = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_BreakpointID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 20, + 198, + 20, + 99, + 99, + 29, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXBreakpointsDataSource_ActionID, + PBXBreakpointsDataSource_TypeID, + PBXBreakpointsDataSource_BreakpointID, + PBXBreakpointsDataSource_UseID, + PBXBreakpointsDataSource_LocationID, + PBXBreakpointsDataSource_ConditionID, + PBXBreakpointsDataSource_IgnoreCountID, + PBXBreakpointsDataSource_ContinueID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXBookmarksDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXBookmarksDataSource_NameID; + PBXFileTableDataSourceColumnWidthsKey = ( + 200, + 200, + 580.58349609375, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXBookmarksDataSource_LocationID, + PBXBookmarksDataSource_NameID, + PBXBookmarksDataSource_CommentsID, + ); + }; + PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 771, + 20, + 48, + 43, + 43, + 20, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + PBXFileDataSource_Target_ColumnID, + ); + }; + PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = { + PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; + PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; + PBXFileTableDataSourceColumnWidthsKey = ( + 20, + 731, + 60, + 20, + 48.16259765625, + 43, + 43, + ); + PBXFileTableDataSourceColumnsKey = ( + PBXFileDataSource_FiletypeID, + PBXFileDataSource_Filename_ColumnID, + PBXTargetDataSource_PrimaryAttribute, + PBXFileDataSource_Built_ColumnID, + PBXFileDataSource_ObjectSize_ColumnID, + PBXFileDataSource_Errors_ColumnID, + PBXFileDataSource_Warnings_ColumnID, + ); + }; + PBXPerProjectTemplateStateSaveDate = 316626383; + PBXWorkspaceStateSaveDate = 316626383; + }; + perUserProjectItems = { + 1F17508512A972DF004A0B42 /* PBXTextBookmark */ = 1F17508512A972DF004A0B42 /* PBXTextBookmark */; + 1F27470412D905CA00339B4F /* PBXTextBookmark */ = 1F27470412D905CA00339B4F /* PBXTextBookmark */; + 1F2F793712BD93A600F073BE /* PBXTextBookmark */ = 1F2F793712BD93A600F073BE /* PBXTextBookmark */; + 1F618EAC12DB5D0700E500D9 /* PBXTextBookmark */ = 1F618EAC12DB5D0700E500D9 /* PBXTextBookmark */; + 1F618ED112DB60D100E500D9 /* PBXTextBookmark */ = 1F618ED112DB60D100E500D9 /* PBXTextBookmark */; + 1F618ED212DB60D100E500D9 /* PBXTextBookmark */ = 1F618ED212DB60D100E500D9 /* PBXTextBookmark */; + 1F618ED312DB60D100E500D9 /* PBXTextBookmark */ = 1F618ED312DB60D100E500D9 /* PBXTextBookmark */; + 1F618ED412DB60D100E500D9 /* PBXTextBookmark */ = 1F618ED412DB60D100E500D9 /* PBXTextBookmark */; + 1F618ED512DB60D100E500D9 /* PBXTextBookmark */ = 1F618ED512DB60D100E500D9 /* PBXTextBookmark */; + 1F618ED612DB60D100E500D9 /* PBXTextBookmark */ = 1F618ED612DB60D100E500D9 /* PBXTextBookmark */; + 1F618F0212DB665B00E500D9 /* PBXTextBookmark */ = 1F618F0212DB665B00E500D9 /* PBXTextBookmark */; + 1F618F0312DB665B00E500D9 /* PlistBookmark */ = 1F618F0312DB665B00E500D9 /* PlistBookmark */; + 1F618F0412DB665B00E500D9 /* PBXTextBookmark */ = 1F618F0412DB665B00E500D9 /* PBXTextBookmark */; + 1F618F0512DB665B00E500D9 /* PBXTextBookmark */ = 1F618F0512DB665B00E500D9 /* PBXTextBookmark */; + 1F8D1E4212DF5A0D00571730 /* PBXTextBookmark */ = 1F8D1E4212DF5A0D00571730 /* PBXTextBookmark */; + 1F8D1E4312DF5A0D00571730 /* PBXTextBookmark */ = 1F8D1E4312DF5A0D00571730 /* PBXTextBookmark */; + 1F8D1E4412DF5A0D00571730 /* PBXTextBookmark */ = 1F8D1E4412DF5A0D00571730 /* PBXTextBookmark */; + 1F98DCA9124C691A004289ED /* PBXTextBookmark */ = 1F98DCA9124C691A004289ED /* PBXTextBookmark */; + 1F98DCAD124C691A004289ED /* PBXBookmark */ = 1F98DCAD124C691A004289ED /* PBXBookmark */; + }; + sourceControlManager = 1F68211B12493A5400A03CED /* Source Control */; + userBuildSettings = { + }; + }; + 2A37F4ACFDCFA73011CA2CEA /* MyDocument.m */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {1748, 1755}}"; + sepNavSelRange = "{3758, 0}"; + sepNavVisRange = "{537, 3377}"; + }; + }; + 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */ = { + uiCtxt = { + sepNavIntBoundsRect = "{{0, 0}, {949, 1262}}"; + sepNavSelRange = "{0, 0}"; + sepNavVisRange = "{0, 573}"; + }; + }; + 8D15AC270486D014006FF6A4 /* Twittia */ = { + activeExec = 0; + executables = ( + 1F68210012493A3400A03CED /* Twittia */, + ); + }; +} diff --git a/Mac/Bungloo.xcodeproj/project.pbxproj b/Mac/Bungloo.xcodeproj/project.pbxproj new file mode 100644 index 0000000..b83b54a --- /dev/null +++ b/Mac/Bungloo.xcodeproj/project.pbxproj @@ -0,0 +1,448 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1DDD582C0DA1D0D100B32029 /* NewMessageWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58280DA1D0D100B32029 /* NewMessageWindow.xib */; }; + 1DDD582D0DA1D0D100B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD582A0DA1D0D100B32029 /* MainMenu.xib */; }; + 1F122D49118E1DE100E83B77 /* Icon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1F122D48118E1DE100E83B77 /* Icon.icns */; }; + 1F132C791666CD9700E4E661 /* TB_SendTemplate.png in Resources */ = {isa = PBXBuildFile; fileRef = 1F132C781666CD9700E4E661 /* TB_SendTemplate.png */; }; + 1F1990C6117BCA960049BEA7 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F1990C5117BCA960049BEA7 /* ApplicationServices.framework */; }; + 1F1C80F916482A250010B409 /* WebKit in Resources */ = {isa = PBXBuildFile; fileRef = 1F1C80F816482A250010B409 /* WebKit */; }; + 1F2D79BD165E8C6B000E8428 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F2D79BC165E8C6B000E8428 /* CoreLocation.framework */; }; + 1F303BE31660752700891D71 /* QuickLook.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F303BE21660752700891D71 /* QuickLook.framework */; }; + 1F3F129E164F202000C7C983 /* dsa_pub.pem in Resources */ = {isa = PBXBuildFile; fileRef = 1F3F129D164F202000C7C983 /* dsa_pub.pem */; }; + 1F618ECA12DB5E6100E500D9 /* PostModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F618EC912DB5E6100E500D9 /* PostModel.m */; }; + 1F70619F1178FBB300C85707 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F70619E1178FBB300C85707 /* Carbon.framework */; }; + 1F77DB47118C5F1C007C7F1E /* Constants.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F77DB46118C5F1C007C7F1E /* Constants.m */; }; + 1F880B6B165EE0F60022A84D /* NSData+Base64.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F880B6A165EE0F60022A84D /* NSData+Base64.m */; }; + 1F880B6E165FE8890022A84D /* MimeType.m in Sources */ = {isa = PBXBuildFile; fileRef = 1F880B6D165FE8890022A84D /* MimeType.m */; }; + 1FA09847144602530079E258 /* libicucore.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FA09846144602530079E258 /* libicucore.dylib */; }; + 1FC254A01427DFAD0035D84B /* AccessToken.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FC2549B1427D9930035D84B /* AccessToken.m */; }; + 1FDEF722164EFE9100F927F3 /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FDEF721164EFE9100F927F3 /* Growl.framework */; }; + 1FDEF723164EFF3100F927F3 /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1FDEF721164EFE9100F927F3 /* Growl.framework */; }; + 1FDEF726164F094600F927F3 /* Growl Registration Ticket.growlRegDict in Resources */ = {isa = PBXBuildFile; fileRef = 1FDEF724164F079800F927F3 /* Growl Registration Ticket.growlRegDict */; }; + 1FE2FC93117A818D000504B0 /* Sparkle.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FE2FC92117A818D000504B0 /* Sparkle.framework */; }; + 1FE2FCA4117A83B1000504B0 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1FE2FC92117A818D000504B0 /* Sparkle.framework */; }; + 1FFA36D71177D879006C8562 /* Controller.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FFA36D31177D879006C8562 /* Controller.m */; }; + 1FFA36D81177D879006C8562 /* ViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1FFA36D51177D879006C8562 /* ViewDelegate.m */; }; + 1FFA37071177DAF4006C8562 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1FFA37061177DAF4006C8562 /* WebKit.framework */; }; + 6B68359B166015C4004F4732 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B68359A166015C4004F4732 /* Security.framework */; }; + 8D15AC2C0486D014006FF6A4 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */; }; + 8D15AC2F0486D014006FF6A4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165FFE840EACC02AAC07 /* InfoPlist.strings */; }; + 8D15AC310486D014006FF6A4 /* NewMessageWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A37F4ACFDCFA73011CA2CEA /* NewMessageWindow.m */; settings = {ATTRIBUTES = (); }; }; + 8D15AC320486D014006FF6A4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A37F4B0FDCFA73011CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; + 8D15AC340486D014006FF6A4 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 1FE2FCA1117A82E1000504B0 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 1FE2FCA4117A83B1000504B0 /* Sparkle.framework in CopyFiles */, + 1FDEF723164EFF3100F927F3 /* Growl.framework in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 089C1660FE840EACC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 13E42FBA07B3F13500E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; + 1DDD58290DA1D0D100B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/NewMessageWindow.xib; sourceTree = ""; }; + 1DDD582B0DA1D0D100B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; + 1F122D48118E1DE100E83B77 /* Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Icon.icns; sourceTree = ""; }; + 1F132C781666CD9700E4E661 /* TB_SendTemplate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = TB_SendTemplate.png; sourceTree = ""; }; + 1F1990C5117BCA960049BEA7 /* ApplicationServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ApplicationServices.framework; path = System/Library/Frameworks/ApplicationServices.framework; sourceTree = SDKROOT; }; + 1F1C80F816482A250010B409 /* WebKit */ = {isa = PBXFileReference; lastKnownFileType = folder; name = WebKit; path = ../WebKit; sourceTree = ""; }; + 1F2D79BC165E8C6B000E8428 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = /System/Library/Frameworks/CoreLocation.framework; sourceTree = ""; }; + 1F303BE21660752700891D71 /* QuickLook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuickLook.framework; path = /System/Library/Frameworks/QuickLook.framework; sourceTree = ""; }; + 1F3F129D164F202000C7C983 /* dsa_pub.pem */ = {isa = PBXFileReference; lastKnownFileType = text; name = dsa_pub.pem; path = publish/dsa_pub.pem; sourceTree = ""; }; + 1F55BA1216C852FB009F0306 /* Bungloo_Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Bungloo_Prefix.pch; sourceTree = ""; }; + 1F618EC812DB5E6100E500D9 /* PostModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = PostModel.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 1F618EC912DB5E6100E500D9 /* PostModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PostModel.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 1F70619E1178FBB300C85707 /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; + 1F77DB45118C5F1C007C7F1E /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Constants.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 1F77DB46118C5F1C007C7F1E /* Constants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = Constants.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 1F880B69165EE0F60022A84D /* NSData+Base64.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Base64.h"; sourceTree = ""; }; + 1F880B6A165EE0F60022A84D /* NSData+Base64.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Base64.m"; sourceTree = ""; }; + 1F880B6C165FE8890022A84D /* MimeType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MimeType.h; sourceTree = ""; }; + 1F880B6D165FE8890022A84D /* MimeType.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MimeType.m; sourceTree = ""; }; + 1FA09846144602530079E258 /* libicucore.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libicucore.dylib; path = usr/lib/libicucore.dylib; sourceTree = SDKROOT; }; + 1FC2549A1427D9930035D84B /* AccessToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = AccessToken.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 1FC2549B1427D9930035D84B /* AccessToken.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = AccessToken.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 1FDEF721164EFE9100F927F3 /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Growl.framework; sourceTree = ""; }; + 1FDEF724164F079800F927F3 /* Growl Registration Ticket.growlRegDict */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "Growl Registration Ticket.growlRegDict"; sourceTree = ""; }; + 1FE2FC92117A818D000504B0 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Sparkle.framework; sourceTree = ""; }; + 1FFA36D21177D879006C8562 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = Controller.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 1FFA36D31177D879006C8562 /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = Controller.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 1FFA36D41177D879006C8562 /* ViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewDelegate.h; sourceTree = ""; }; + 1FFA36D51177D879006C8562 /* ViewDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewDelegate.m; sourceTree = ""; }; + 1FFA37061177DAF4006C8562 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + 2A37F4ACFDCFA73011CA2CEA /* NewMessageWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = NewMessageWindow.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 2A37F4AEFDCFA73011CA2CEA /* NewMessageWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = NewMessageWindow.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 2A37F4B0FDCFA73011CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = main.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 2A37F4BAFDCFA73011CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = English; path = English.lproj/Credits.rtf; sourceTree = ""; }; + 2A37F4C4FDCFA73011CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 2A37F4C5FDCFA73011CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 6B68359A166015C4004F4732 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = ""; }; + 8D15AC360486D014006FF6A4 /* Bungloo-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Bungloo-Info.plist"; sourceTree = ""; }; + 8D15AC370486D014006FF6A4 /* Bungloo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Bungloo.app; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8D15AC330486D014006FF6A4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1F303BE31660752700891D71 /* QuickLook.framework in Frameworks */, + 6B68359B166015C4004F4732 /* Security.framework in Frameworks */, + 1F2D79BD165E8C6B000E8428 /* CoreLocation.framework in Frameworks */, + 1FDEF722164EFE9100F927F3 /* Growl.framework in Frameworks */, + 1FA09847144602530079E258 /* libicucore.dylib in Frameworks */, + 8D15AC340486D014006FF6A4 /* Cocoa.framework in Frameworks */, + 1FFA37071177DAF4006C8562 /* WebKit.framework in Frameworks */, + 1F70619F1178FBB300C85707 /* Carbon.framework in Frameworks */, + 1FE2FC93117A818D000504B0 /* Sparkle.framework in Frameworks */, + 1F1990C6117BCA960049BEA7 /* ApplicationServices.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 1058C7A6FEA54F5311CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 1F303BE21660752700891D71 /* QuickLook.framework */, + 6B68359A166015C4004F4732 /* Security.framework */, + 1F2D79BC165E8C6B000E8428 /* CoreLocation.framework */, + 1FDEF721164EFE9100F927F3 /* Growl.framework */, + 1FE2FC92117A818D000504B0 /* Sparkle.framework */, + 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */, + 1FFA37061177DAF4006C8562 /* WebKit.framework */, + 1F70619E1178FBB300C85707 /* Carbon.framework */, + 1F1990C5117BCA960049BEA7 /* ApplicationServices.framework */, + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7A8FEA54F5311CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 2A37F4C4FDCFA73011CA2CEA /* AppKit.framework */, + 13E42FBA07B3F13500E4EEF1 /* CoreData.framework */, + 2A37F4C5FDCFA73011CA2CEA /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 19C28FB0FE9D524F11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D15AC370486D014006FF6A4 /* Bungloo.app */, + ); + name = Products; + sourceTree = ""; + }; + 2A37F4AAFDCFA73011CA2CEA /* Twittia 2 */ = { + isa = PBXGroup; + children = ( + 1FA09846144602530079E258 /* libicucore.dylib */, + 2A37F4ABFDCFA73011CA2CEA /* Classes */, + 2A37F4AFFDCFA73011CA2CEA /* Other Sources */, + 2A37F4B8FDCFA73011CA2CEA /* Resources */, + 2A37F4C3FDCFA73011CA2CEA /* Frameworks */, + 19C28FB0FE9D524F11CA2CBB /* Products */, + ); + name = "Twittia 2"; + sourceTree = ""; + }; + 2A37F4ABFDCFA73011CA2CEA /* Classes */ = { + isa = PBXGroup; + children = ( + 1FFA36D21177D879006C8562 /* Controller.h */, + 1FFA36D31177D879006C8562 /* Controller.m */, + 1FFA36D41177D879006C8562 /* ViewDelegate.h */, + 1FFA36D51177D879006C8562 /* ViewDelegate.m */, + 2A37F4AEFDCFA73011CA2CEA /* NewMessageWindow.h */, + 2A37F4ACFDCFA73011CA2CEA /* NewMessageWindow.m */, + 1F77DB45118C5F1C007C7F1E /* Constants.h */, + 1F77DB46118C5F1C007C7F1E /* Constants.m */, + 1F618EC812DB5E6100E500D9 /* PostModel.h */, + 1F618EC912DB5E6100E500D9 /* PostModel.m */, + 1FC2549A1427D9930035D84B /* AccessToken.h */, + 1FC2549B1427D9930035D84B /* AccessToken.m */, + 1F880B69165EE0F60022A84D /* NSData+Base64.h */, + 1F880B6A165EE0F60022A84D /* NSData+Base64.m */, + 1F880B6C165FE8890022A84D /* MimeType.h */, + 1F880B6D165FE8890022A84D /* MimeType.m */, + ); + name = Classes; + sourceTree = ""; + }; + 2A37F4AFFDCFA73011CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 1F55BA1216C852FB009F0306 /* Bungloo_Prefix.pch */, + 2A37F4B0FDCFA73011CA2CEA /* main.m */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 2A37F4B8FDCFA73011CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + 1F1C80F816482A250010B409 /* WebKit */, + 1F122D48118E1DE100E83B77 /* Icon.icns */, + 1F3F129D164F202000C7C983 /* dsa_pub.pem */, + 1F132C781666CD9700E4E661 /* TB_SendTemplate.png */, + 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */, + 8D15AC360486D014006FF6A4 /* Bungloo-Info.plist */, + 089C165FFE840EACC02AAC07 /* InfoPlist.strings */, + 1DDD58280DA1D0D100B32029 /* NewMessageWindow.xib */, + 1DDD582A0DA1D0D100B32029 /* MainMenu.xib */, + 1FDEF724164F079800F927F3 /* Growl Registration Ticket.growlRegDict */, + ); + name = Resources; + sourceTree = ""; + }; + 2A37F4C3FDCFA73011CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A6FEA54F5311CA2CBB /* Linked Frameworks */, + 1058C7A8FEA54F5311CA2CBB /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8D15AC270486D014006FF6A4 /* Bungloo */ = { + isa = PBXNativeTarget; + buildConfigurationList = C05733C708A9546B00998B17 /* Build configuration list for PBXNativeTarget "Bungloo" */; + buildPhases = ( + 8D15AC2B0486D014006FF6A4 /* Resources */, + 8D15AC300486D014006FF6A4 /* Sources */, + 8D15AC330486D014006FF6A4 /* Frameworks */, + 1FE2FCA1117A82E1000504B0 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Bungloo; + productInstallPath = "$(HOME)/Applications"; + productName = "Twittia 2"; + productReference = 8D15AC370486D014006FF6A4 /* Bungloo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 2A37F4A9FDCFA73011CA2CEA /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0450; + }; + buildConfigurationList = C05733CB08A9546B00998B17 /* Build configuration list for PBXProject "Bungloo" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 2A37F4AAFDCFA73011CA2CEA /* Twittia 2 */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8D15AC270486D014006FF6A4 /* Bungloo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8D15AC2B0486D014006FF6A4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1F3F129E164F202000C7C983 /* dsa_pub.pem in Resources */, + 1FDEF726164F094600F927F3 /* Growl Registration Ticket.growlRegDict in Resources */, + 8D15AC2C0486D014006FF6A4 /* Credits.rtf in Resources */, + 8D15AC2F0486D014006FF6A4 /* InfoPlist.strings in Resources */, + 1DDD582C0DA1D0D100B32029 /* NewMessageWindow.xib in Resources */, + 1DDD582D0DA1D0D100B32029 /* MainMenu.xib in Resources */, + 1F122D49118E1DE100E83B77 /* Icon.icns in Resources */, + 1F1C80F916482A250010B409 /* WebKit in Resources */, + 1F132C791666CD9700E4E661 /* TB_SendTemplate.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8D15AC300486D014006FF6A4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1FC254A01427DFAD0035D84B /* AccessToken.m in Sources */, + 8D15AC310486D014006FF6A4 /* NewMessageWindow.m in Sources */, + 8D15AC320486D014006FF6A4 /* main.m in Sources */, + 1FFA36D71177D879006C8562 /* Controller.m in Sources */, + 1FFA36D81177D879006C8562 /* ViewDelegate.m in Sources */, + 1F77DB47118C5F1C007C7F1E /* Constants.m in Sources */, + 1F618ECA12DB5E6100E500D9 /* PostModel.m in Sources */, + 1F880B6B165EE0F60022A84D /* NSData+Base64.m in Sources */, + 1F880B6E165FE8890022A84D /* MimeType.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 089C165FFE840EACC02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C1660FE840EACC02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 1DDD58280DA1D0D100B32029 /* NewMessageWindow.xib */ = { + isa = PBXVariantGroup; + children = ( + 1DDD58290DA1D0D100B32029 /* English */, + ); + name = NewMessageWindow.xib; + sourceTree = ""; + }; + 1DDD582A0DA1D0D100B32029 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 1DDD582B0DA1D0D100B32029 /* English */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; + 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */ = { + isa = PBXVariantGroup; + children = ( + 2A37F4BAFDCFA73011CA2CEA /* English */, + ); + name = Credits.rtf; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + C05733C808A9546B00998B17 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)\"", + ); + GCC_DYNAMIC_NO_PIC = NO; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Bungloo_Prefix.pch; + INFOPLIST_FILE = "Bungloo-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = Bungloo; + SDKROOT = ""; + }; + name = Debug; + }; + C05733C908A9546B00998B17 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\"$(SRCROOT)\"", + ); + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = Bungloo_Prefix.pch; + INFOPLIST_FILE = "Bungloo-Info.plist"; + INSTALL_PATH = "$(HOME)/Applications"; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = Bungloo; + SDKROOT = ""; + }; + name = Release; + }; + C05733CC08A9546B00998B17 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.5; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = Bungloo; + SDKROOT = ""; + }; + name = Debug; + }; + C05733CD08A9546B00998B17 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.5; + ONLY_ACTIVE_ARCH = NO; + PRODUCT_NAME = Bungloo; + SDKROOT = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + C05733C708A9546B00998B17 /* Build configuration list for PBXNativeTarget "Bungloo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C05733C808A9546B00998B17 /* Debug */, + C05733C908A9546B00998B17 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; + C05733CB08A9546B00998B17 /* Build configuration list for PBXProject "Bungloo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C05733CC08A9546B00998B17 /* Debug */, + C05733CD08A9546B00998B17 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Debug; + }; +/* End XCConfigurationList section */ + }; + rootObject = 2A37F4A9FDCFA73011CA2CEA /* Project object */; +} diff --git a/Mac/Bungloo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Mac/Bungloo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..0fa3cc5 --- /dev/null +++ b/Mac/Bungloo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Mac/Bungloo.xcodeproj/project.xcworkspace/xcuserdata/jeena.xcuserdatad/WorkspaceSettings.xcsettings b/Mac/Bungloo.xcodeproj/project.xcworkspace/xcuserdata/jeena.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..659c876 --- /dev/null +++ b/Mac/Bungloo.xcodeproj/project.xcworkspace/xcuserdata/jeena.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,10 @@ + + + + + HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges + + SnapshotAutomaticallyBeforeSignificantChanges + + + diff --git a/Mac/Bungloo.xcodeproj/xcuserdata/jeena.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist b/Mac/Bungloo.xcodeproj/xcuserdata/jeena.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist new file mode 100644 index 0000000..a5446f1 --- /dev/null +++ b/Mac/Bungloo.xcodeproj/xcuserdata/jeena.xcuserdatad/xcdebugger/Breakpoints.xcbkptlist @@ -0,0 +1,18 @@ + + + + + + + diff --git a/Mac/Bungloo.xcodeproj/xcuserdata/jeena.xcuserdatad/xcschemes/Bungloo.xcscheme b/Mac/Bungloo.xcodeproj/xcuserdata/jeena.xcuserdatad/xcschemes/Bungloo.xcscheme new file mode 100644 index 0000000..c8d35d9 --- /dev/null +++ b/Mac/Bungloo.xcodeproj/xcuserdata/jeena.xcuserdatad/xcschemes/Bungloo.xcscheme @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mac/Bungloo.xcodeproj/xcuserdata/jeena.xcuserdatad/xcschemes/xcschememanagement.plist b/Mac/Bungloo.xcodeproj/xcuserdata/jeena.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..20fd17d --- /dev/null +++ b/Mac/Bungloo.xcodeproj/xcuserdata/jeena.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + Bungloo.xcscheme + + orderHint + 1 + + + SuppressBuildableAutocreation + + 8D15AC270486D014006FF6A4 + + primary + + + + + diff --git a/Mac/Bungloo_Prefix.pch b/Mac/Bungloo_Prefix.pch new file mode 100644 index 0000000..f7b0d9b --- /dev/null +++ b/Mac/Bungloo_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'Tentia' target in the 'Tentia' project +// + +#ifdef __OBJC__ +#import +#endif diff --git a/Mac/Constants.h b/Mac/Constants.h new file mode 100644 index 0000000..11a32e2 --- /dev/null +++ b/Mac/Constants.h @@ -0,0 +1,22 @@ +// +// Constants.h +// bungloo +// +// Created by Jeena on 01.05.10. +// Licence: BSD (see attached LICENCE.txt file). +// + +#import +#import + + +@interface Constants : NSObject { + +} + +#define APP_NAME @"Bungloo" +#define MESSAGE_MAX_LENGTH 256 + ++ (NSString *)stringFromVirtualKeyCode:(NSInteger)code; + +@end diff --git a/Mac/Constants.m b/Mac/Constants.m new file mode 100644 index 0000000..d70242a --- /dev/null +++ b/Mac/Constants.m @@ -0,0 +1,220 @@ +// +// Constants.m +// bungloo +// +// Created by Jeena on 01.05.10. +// Licence: BSD (see attached LICENCE.txt file). +// + +#import "Constants.h" + + +@implementation Constants + ++ (NSString *)stringFromVirtualKeyCode:(NSInteger)code { + NSString *string = nil; + switch (code) { + case kVK_ANSI_A: + string = @"A"; + break; + case kVK_ANSI_S: + string = @"S"; + break; + case kVK_ANSI_D: + string = @"D"; + break; + case kVK_ANSI_F: + string = @"F"; + break; + case kVK_ANSI_H: + string = @"H"; + break; + case kVK_ANSI_G: + string = @"G"; + break; + case kVK_ANSI_Z: + string = @"Z"; + break; + case kVK_ANSI_X: + string = @"X"; + break; + case kVK_ANSI_C: + string = @"C"; + break; + case kVK_ANSI_V: + string = @"V"; + break; + case kVK_ANSI_B: + string = @"B"; + break; + case kVK_ANSI_Q: + string = @"Q"; + break; + case kVK_ANSI_W: + string = @"W"; + break; + case kVK_ANSI_E: + string = @"E"; + break; + case kVK_ANSI_R: + string = @"R"; + break; + case kVK_ANSI_Y: + string = @"Y"; + break; + case kVK_ANSI_T: + string = @"T"; + break; + case kVK_ANSI_1: + string = @"1"; + break; + case kVK_ANSI_2: + string = @"2"; + break; + case kVK_ANSI_3: + string = @"3"; + break; + case kVK_ANSI_4: + string = @"4"; + break; + case kVK_ANSI_6: + string = @"6"; + break; + case kVK_ANSI_5: + string = @"5"; + break; + case kVK_ANSI_Equal: + string = @"="; + break; + case kVK_ANSI_9: + string = @"9"; + break; + case kVK_ANSI_7: + string = @"7"; + break; + case kVK_ANSI_Minus: + string = @"-"; + break; + case kVK_ANSI_8: + string = @"8"; + break; + case kVK_ANSI_0: + string = @"0"; + break; + case kVK_ANSI_RightBracket: + string = @")"; + break; + case kVK_ANSI_O: + string = @"0"; + break; + case kVK_ANSI_U: + string = @"U"; + break; + case kVK_ANSI_LeftBracket: + string = @"("; + break; + case kVK_ANSI_I: + string = @"I"; + break; + case kVK_ANSI_P: + string = @"P"; + break; + case kVK_ANSI_L: + string = @"L"; + break; + case kVK_ANSI_J: + string = @"J"; + break; + case kVK_ANSI_Quote: + string = @"\""; + break; + case kVK_ANSI_K: + string = @"K"; + break; + case kVK_ANSI_Semicolon: + string = @";"; + break; + case kVK_ANSI_Backslash: + string = @"\\"; + break; + case kVK_ANSI_Comma: + string = @","; + break; + case kVK_ANSI_Slash: + string = @"/"; + break; + case kVK_ANSI_N: + string = @"N"; + break; + case kVK_ANSI_M: + string = @"M"; + break; + case kVK_ANSI_Period: + string = @"."; + break; + case kVK_ANSI_Grave: + string = @"`"; + break; + case kVK_ANSI_KeypadDecimal: + string = @"."; + break; + case kVK_ANSI_KeypadMultiply: + string = @"*"; + break; + case kVK_ANSI_KeypadPlus: + string = @"+"; + break; + case kVK_ANSI_KeypadClear: + string = @""; + break; + case kVK_ANSI_KeypadDivide: + string = @"/"; + break; + case kVK_ANSI_KeypadEnter: + string = @"⎆"; + break; + case kVK_ANSI_KeypadMinus: + string = @"-"; + break; + case kVK_ANSI_KeypadEquals: + string = @"="; + break; + case kVK_ANSI_Keypad0: + string = @"0"; + break; + case kVK_ANSI_Keypad1: + string = @"1"; + break; + case kVK_ANSI_Keypad2: + string = @"2"; + break; + case kVK_ANSI_Keypad3: + string = @"3"; + break; + case kVK_ANSI_Keypad4: + string = @"4"; + break; + case kVK_ANSI_Keypad5: + string = @"5"; + break; + case kVK_ANSI_Keypad6: + string = @"6"; + break; + case kVK_ANSI_Keypad7: + string = @"7"; + break; + case kVK_ANSI_Keypad8: + string = @"8"; + break; + case kVK_ANSI_Keypad9: + string = @"9"; + break; + default: + string = nil; + break; + } + + return string; +} + +@end diff --git a/Mac/Controller.h b/Mac/Controller.h new file mode 100644 index 0000000..b06e762 --- /dev/null +++ b/Mac/Controller.h @@ -0,0 +1,83 @@ +// +// Controller.h +// bungloo +// +// Created by Jeena on 15.04.10. +// Licence: BSD (see attached LICENCE.txt file). +// + +#import +#import +#import "ViewDelegate.h" +#import +#import "Constants.h" +#import "AccessToken.h" +#import +#import "NSData+Base64.h" +#import "MimeType.h" + +@interface Controller : NSObject { + IBOutlet WebView *timelineView; + IBOutlet NSWindow *timelineViewWindow; + NSPanel *openProfileWindow; + NSWindow *loginViewWindow; + NSTextField *loginEntityTextField; + NSProgressIndicator *loginActivityIndicator; + IBOutlet NSMenuItem *globalHotkeyMenuItem; + IBOutlet NSImageView *logoLayer; + ViewDelegate *viewDelegate; + WebView *oauthView; + AccessToken *accessToken; + NSTextField *showProfileTextField; + +} + +@property (assign) IBOutlet WebView *timelineView; +@property (assign) IBOutlet NSWindow *timelineViewWindow; +@property (assign) IBOutlet NSPanel *openProfileWindow; + +@property (assign) IBOutlet NSWindow *loginViewWindow; +@property (assign) IBOutlet NSTextField *loginEntityTextField; +@property (assign) IBOutlet NSProgressIndicator *loginActivityIndicator; +@property (retain, nonatomic) IBOutlet NSMenuItem *globalHotkeyMenuItem; +@property (retain, nonatomic) IBOutlet NSImageView *logoLayer; +@property (retain, nonatomic) IBOutlet ViewDelegate *viewDelegate; +@property (retain, nonatomic) WebView *oauthView; +@property (retain, nonatomic) AccessToken *accessToken; +@property (assign) IBOutlet NSTextField *showProfileTextField; + + +- (void)initOauth; +- (void)authentificationSucceded:(id)sender; +- (void)authentificationDidNotSucceed:(NSString *)errorMessage; +- (void)initWebViews; +- (void)initHotKeys; +- (void)alertTitle:(NSString *)title withMessage:(NSString *)message; +- (void)openNewMessageWindowInReplyTo:(NSString *)userName statusId:(NSString *)statusId withString:(NSString *)string isPrivate:(BOOL)isPrivate; +- (NSString *)pluginURL; +- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent; +- (void)unreadMentions:(int)count; +- (void)notificateUserAboutMention:(NSString *)text fromName:(NSString *)name withPostId:(NSString *)postId andEntity:(NSString *)entity; + +- (void)openURL:(NSString *)url; +- (IBAction)showProfile:(id)sender; +- (void)notificateViewsAboutDeletedPostWithId:(NSString *)postId byEntity:(NSString*)entity; + +- (void)setString:(NSString *)string forKey:(NSString *)aKey; +- (void)setSecret:(NSString *)string; +- (NSString *)secret; +- (NSString *)stringForKey:(NSString *)aKey; +- (void)loggedIn; + +- (void)stringFromFile:(NSString *)file url: (NSURL **) url content: (NSString **) content; + +- (IBAction)login:(id)sender; +- (IBAction)logout:(id)sender; + +- (IBAction)showConversationForPostId:(NSString *)postId andEntity:(NSString *)entity; + +- (IBAction)clearCache:(id)sender; + +OSStatus handler(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData); + +@end diff --git a/Mac/Controller.m b/Mac/Controller.m new file mode 100644 index 0000000..0cf5147 --- /dev/null +++ b/Mac/Controller.m @@ -0,0 +1,475 @@ +// +// Controller.m +// bungloo +// +// Created by Jeena on 15.04.10. +// Licence: BSD (see attached LICENCE.txt file). +// + +#import "Controller.h" +#import "NewMessageWindow.h" +#import "PostModel.h" +#import "NSData+Base64.h" + +@implementation Controller +@synthesize showProfileTextField; +@synthesize openProfileWindow; +@synthesize loginViewWindow; +@synthesize loginEntityTextField; +@synthesize loginActivityIndicator; +@synthesize timelineView, timelineViewWindow; +@synthesize globalHotkeyMenuItem, viewDelegate; +@synthesize logoLayer; +@synthesize oauthView, accessToken; + +- (void)awakeFromNib +{ + [timelineViewWindow setExcludedFromWindowsMenu:YES]; + + [self initHotKeys]; + + [GrowlApplicationBridge setGrowlDelegate:self]; + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self + selector:@selector(openNewMessageWindow:) + name:@"openNewMessageWindow" + object:nil]; + [nc addObserver:self + selector:@selector(sendPost:) + name:@"sendPost" + object:nil]; + [nc addObserver:self + selector:@selector(authentificationSucceded:) + name:@"authentificationSucceded" + object:nil]; + [nc addObserver:self + selector:@selector(getPostUpdates:) + name:@"getPostUpdates" + object:nil]; + + NSAppleEventManager *appleEventManager = [NSAppleEventManager sharedAppleEventManager]; + [appleEventManager setEventHandler:self + andSelector:@selector(handleGetURLEvent:withReplyEvent:) + forEventClass:kInternetEventClass + andEventID:kAEGetURL]; + + + viewDelegate = [[ViewDelegate alloc] init]; + accessToken = [[AccessToken alloc] init]; + + BOOL forceLogin = NO; + /* + if (![accessToken stringForKey:@"version-0.6.0-new-login"]) { + [self logout:self]; + forceLogin = YES; + [accessToken setString:nil forKey:@"entity"]; + [accessToken setString:@"yes" forKey:@"version-0.6.0-new-login"]; + }*/ + + if (forceLogin || ![accessToken stringForKey:@"user_access_token"] || ![accessToken secret]) { + [timelineViewWindow performClose:self]; + [self.loginViewWindow makeKeyAndOrderFront:self]; + [self initOauth]; + } else { + [timelineViewWindow makeKeyAndOrderFront:self]; + [self initWebViews]; + } +} + +# pragma mark Init + +- (void)stringFromFile:(NSString *)file url: (NSURL **) url content: (NSString **) content +{ + NSString *path = [[[NSBundle mainBundle] resourcePath] stringByAppendingFormat: @"/WebKit/%@", file]; + *url = [NSURL fileURLWithPath: path]; + *content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil]; +} + +- (void)initOauth +{ + if (!oauthView) { + NSString *index_string; + NSURL *url; + + [self stringFromFile: @"index.html" url: &url content: &index_string]; + + oauthView = [[WebView alloc] init]; + viewDelegate.oauthView = oauthView; + [[oauthView mainFrame] loadHTMLString:index_string baseURL:url]; + [oauthView setFrameLoadDelegate:viewDelegate]; + [oauthView setPolicyDelegate:viewDelegate]; + [oauthView setUIDelegate:viewDelegate]; + [[oauthView windowScriptObject] setValue:self forKey:@"controller"]; + + } +} + +- (void)initWebViews +{ + + if (viewDelegate.timelineView != timelineView) + { + NSString *index_string; + NSURL *url; + + [self initOauth]; + + [self stringFromFile: @"index.html" url: &url content: &index_string]; + + viewDelegate.timelineView = timelineView; + [[timelineView mainFrame] loadHTMLString:index_string baseURL:url]; + [timelineView setFrameLoadDelegate:viewDelegate]; + [timelineView setPolicyDelegate:viewDelegate]; + [timelineView setUIDelegate:viewDelegate]; + [[timelineView windowScriptObject] setValue:self forKey:@"controller"]; + + } + else + { + [timelineView stringByEvaluatingJavaScriptFromString:@"start('timeline')"]; + } +} + +- (void)initHotKeys +{ + + NSInteger newPostKey = kVK_ANSI_M; // http://boredzo.org/blog/archives/2007-05-22/virtual-key-codes + NSInteger newPostModifierKey = controlKey + cmdKey + optionKey; // cmdKey 256, shitfKey 512, optionKey 2048, controlKey 4096 + + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSInteger defaultsNewPostKey = (NSInteger)[defaults integerForKey:@"newPostKey"]; + + if ([defaults objectForKey:@"newPostKey"] != nil) + { + newPostKey = defaultsNewPostKey; + } + else + { + [defaults setInteger:newPostKey forKey:@"newPostKey"]; + } + + NSInteger defaultsNewPostModifierKey = (NSInteger)[defaults integerForKey:@"newPostModifierKey"]; + if ([defaults objectForKey:@"newPostModifierKey"] != nil) + { + newPostModifierKey = defaultsNewPostModifierKey; + } + else + { + [defaults setInteger:newPostModifierKey forKey:@"newPostModifierKey"]; + } + + [defaults synchronize]; + + NSUInteger cocoaModifiers = 0; + if (newPostModifierKey & shiftKey) cocoaModifiers = cocoaModifiers | NSShiftKeyMask; + if (newPostModifierKey & optionKey) cocoaModifiers = cocoaModifiers | NSAlternateKeyMask; + if (newPostModifierKey & controlKey) cocoaModifiers = cocoaModifiers | NSControlKeyMask; + if (newPostModifierKey & cmdKey) cocoaModifiers = cocoaModifiers | NSCommandKeyMask; + + [globalHotkeyMenuItem setKeyEquivalent:[Constants stringFromVirtualKeyCode:newPostKey]]; + [globalHotkeyMenuItem setKeyEquivalentModifierMask:cocoaModifiers]; + + /* CARBON from http://github.com/Xjs/drama-button/blob/carbon/Drama_ButtonAppDelegate.m */ + + EventTypeSpec eventType; + eventType.eventClass = kEventClassKeyboard; + eventType.eventKind = kEventHotKeyPressed; + + InstallApplicationEventHandler(&handler, 1, &eventType, NULL, NULL); + + EventHotKeyID g_HotKeyID; + g_HotKeyID.id = 1; + + EventHotKeyRef g_HotKeyRef; + + RegisterEventHotKey(newPostKey, newPostModifierKey, g_HotKeyID, GetApplicationEventTarget(), 0, &g_HotKeyRef); + + /* end CARBON */ +} + +- (void)alertTitle:(NSString *)title withMessage:(NSString *)message +{ + NSAlert *alert = [NSAlert alertWithMessageText:title + defaultButton:@"OK" alternateButton:nil otherButton:nil + informativeTextWithFormat:@"%@", message]; + [alert runModal]; +} + +- (void)authentificationSucceded:(id)sender +{ + [loginActivityIndicator stopAnimation:self]; + [self initWebViews]; + [loginViewWindow performClose:self]; +} + +- (void)authentificationDidNotSucceed:(NSString *)errorMessage +{ + [loginActivityIndicator stopAnimation:self]; + [self alertTitle:@"Authenication error" withMessage:errorMessage]; +} + ++ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector +{ + return NO; +} + ++ (BOOL)isKeyExcludedFromWebScript:(const char *)name +{ + return NO; +} + +- (void)setString:(NSString *)string forKey:(NSString *)aKey +{ + [self.accessToken setString:string forKey:aKey]; +} + +- (void)setSecret:(NSString *)string +{ + [self.accessToken setSecret:string]; +} +- (NSString *)secret +{ + return [self.accessToken secret]; +} + +- (NSString *)stringForKey:(NSString *)aKey +{ + return [self.accessToken stringForKey:aKey]; +} + + +#pragma mark Notifications + +-(BOOL)applicationShouldOpenUntitledFile:(NSApplication *)theApplication +{ + return NO; +} + +- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag +{ + [timelineViewWindow makeKeyAndOrderFront:self]; + return NO; +} + +- (IBAction)openNewMessageWindow:(id)sender +{ + [NSApp activateIgnoringOtherApps:YES]; + [[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:nil]; +} + +- (void)openNewMessageWindowInReplyTo:(NSString *)userName statusId:(NSString *)statusId withString:(NSString *)string isPrivate:(BOOL)isPrivate +{ + [NSApp activateIgnoringOtherApps:YES]; + NewMessageWindow *newMessage = (NewMessageWindow *)[[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:nil]; + [newMessage inReplyTo:userName statusId:statusId withString:string]; + [newMessage setIsPrivate:isPrivate]; +} + +- (void)openNewMessageWindowWithString:(NSString *)aString +{ + [NSApp activateIgnoringOtherApps:YES]; + + NSRange range = [aString rangeOfString:@"oauthtoken"]; + + if (range.length > 0) + { + [oauthView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"bungloo.oauth.requestAccessToken('%@')", aString]]; + } + else + { + NewMessageWindow *newPost = (NewMessageWindow *)[[NSDocumentController sharedDocumentController] openUntitledDocumentAndDisplay:YES error:nil]; + [newPost withString:aString]; + } +} + +- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent +{ + NSString *text = [[[event paramDescriptorForKeyword:keyDirectObject] stringValue] substringFromIndex:8]; + [self openNewMessageWindowWithString:[text stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; +} + +- (IBAction)sendPost:(id)sender +{ + PostModel *post = (PostModel *)[sender object]; + NSString *text = [[post.text stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"] stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; + text = [text stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]; + + NSString *locationObject = @"null"; + if (post.location) { + locationObject = [NSString stringWithFormat:@"[%f, %f]", post.location.coordinate.latitude, post.location.coordinate.longitude]; + } + + NSString *imageFilePath = @"null"; + if (post.imageFilePath) { + NSError *error; + NSString *mimeType = [MimeType mimeTypeForFileAtPath:post.imageFilePath error:&error]; + NSData *data = [[NSData alloc] initWithContentsOfFile:post.imageFilePath]; + NSString *base64 = [data base64Encoding_xcd]; + [data release]; + imageFilePath = [NSString stringWithFormat:@"\"data:%@;base64,%@\"", mimeType, base64]; + } + + NSString *isPrivate = @"false"; + if (post.isPrivate) { + isPrivate = @"true"; + } + + NSString *func = [NSString stringWithFormat:@"bungloo.timeline.sendNewMessage(\"%@\", \"%@\", \"%@\", %@, %@, %@)", + text, + post.inReplyTostatusId, + post.inReplyToEntity, + locationObject, + imageFilePath, + isPrivate]; + + [timelineView stringByEvaluatingJavaScriptFromString:func]; +} + +- (NSString *)pluginURL +{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *pathToPlugin = [@"~/Library/Application Support/Bungloo/Plugin.js" stringByExpandingTildeInPath]; + + if([fileManager fileExistsAtPath:pathToPlugin]) + { + return [NSString stringWithFormat:@"%@", [NSURL fileURLWithPath:pathToPlugin]]; + } + return nil; +} + +- (void)unreadMentions:(int)count +{ + if (count > 0) + { + [[[NSApplication sharedApplication] dockTile] setBadgeLabel:[NSString stringWithFormat:@"%i", count]]; + } + else + { + [[[NSApplication sharedApplication] dockTile] setBadgeLabel:nil]; + } + + NSString *script = [NSString stringWithFormat:@"bungloo.sidebar.setUnreadMentions(%i);", count]; + [timelineView stringByEvaluatingJavaScriptFromString:script]; +} + +- (void)notificateUserAboutMention:(NSString *)text fromName:(NSString *)name withPostId:(NSString *)postId andEntity:(NSString *)entity +{ + [GrowlApplicationBridge + notifyWithTitle:[NSString stringWithFormat:@"Mentioned by %@ on Tent", name] + description:text + notificationName:@"Mention" + iconData:nil + priority:0 + isSticky:NO + clickContext:[NSDictionary dictionaryWithObjectsAndKeys: + entity, @"entity", + postId, @"postId", nil]]; +} + +- (void)openURL:(NSString *)url +{ + [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:url]]; +} + +- (IBAction)showProfile:(id)sender +{ + NSString *entity = [self.showProfileTextField stringValue]; + if ([entity rangeOfString:@"."].location != NSNotFound && ([entity hasPrefix:@"http://"] || [entity hasPrefix:@"https://"])) { + NSString *func = [NSString stringWithFormat:@"bungloo.sidebar.onEntityProfile(); bungloo.entityProfile.showProfileForEntity('%@')", entity]; + [timelineView stringByEvaluatingJavaScriptFromString:func]; + } +} + +- (void)notificateViewsAboutDeletedPostWithId:(NSString *)postId byEntity:(NSString*)entity +{ + NSString *f = [NSString stringWithFormat:@".postDeleted('%@', '%@');", postId, entity]; + NSMutableString *fun = [NSMutableString stringWithFormat:@"bungloo.timeline%@", f]; + [fun appendFormat:@"bungloo.mentions%@", f]; + [fun appendFormat:@"bungloo.conversation%@", f]; + [fun appendFormat:@"bungloo.entityProfile%@", f]; + [timelineView stringByEvaluatingJavaScriptFromString:fun]; +} + +- (void)loggedIn +{ + [loginActivityIndicator stopAnimation:self]; + [self initWebViews]; + [loginViewWindow performClose:self]; + [timelineViewWindow makeKeyAndOrderFront:self]; +} + +- (IBAction)login:(id)sender +{ + if ([[loginEntityTextField stringValue] length] > 0) { + [[loginEntityTextField window] makeFirstResponder:nil]; + [loginActivityIndicator startAnimation:self]; + [oauthView stringByEvaluatingJavaScriptFromString:@"bungloo.oauth.authenticate();"]; + } +} + +- (IBAction)logout:(id)sender +{ + [oauthView stringByEvaluatingJavaScriptFromString:@"bungloo.oauth.logout();"]; + + [timelineViewWindow performClose:self]; + [self.loginViewWindow makeKeyAndOrderFront:self]; + + [timelineView stringByEvaluatingJavaScriptFromString:@"bungloo.sidebar.logout();"]; +} + +// Mentions window has been visible +- (void)windowDidBecomeKey:(NSNotification *)notification +{ + +} + +- (void)getPostUpdates:(id)sender +{ + [timelineView stringByEvaluatingJavaScriptFromString:@"bungloo.timeline.getNewData(true)"]; + [timelineView stringByEvaluatingJavaScriptFromString:@"bungloo.mentions.getNewData(true)"]; +} + +- (IBAction)showConversationForPostId:(NSString *)postId andEntity:(NSString *)entity +{ + NSString *js = [NSString stringWithFormat:@"bungloo.sidebar.onConversation(); bungloo.conversation.showStatus('%@', '%@');", postId, entity]; + [timelineView stringByEvaluatingJavaScriptFromString:js]; +} + +- (IBAction)clearCache:(id)sender +{ + [timelineView stringByEvaluatingJavaScriptFromString:@"bungloo.timeline.cache.clear()"]; +} + +- (IBAction)showProfileForEntity:(NSString *)entity +{ + NSString *js = [NSString stringWithFormat:@"bungloo.sidebar.onEntityProfile(); bungloo.entityProfile.showProfileForEntity('%@');", entity]; + [timelineView stringByEvaluatingJavaScriptFromString:js]; +} + +- (void)growlNotificationWasClicked:(id)clickContext +{ + NSDictionary *userInfo = (NSDictionary *)clickContext; + NSString *postId = [userInfo objectForKey:@"postId"]; + NSString *entity = [userInfo objectForKey:@"entity"]; + + [self showConversationForPostId:postId andEntity:entity]; + + NSString *js = [NSString stringWithFormat:@"bungloo.sidebar.onMentions(); bungloo.mentions.mentionRead('%@', '%@');", postId, entity]; + [timelineView stringByEvaluatingJavaScriptFromString:js]; +} + +- (NSString *) applicationNameForGrowl +{ + return @"Bungloo"; +} + +/* CARBON */ + +OSStatus handler(EventHandlerCallRef nextHandler, EventRef theEvent, void* userData) +{ + [[NSNotificationCenter defaultCenter] postNotificationName:@"openNewMessageWindow" object:nil]; + return noErr; +} + +@end diff --git a/Mac/English.lproj/Credits.rtf b/Mac/English.lproj/Credits.rtf new file mode 100644 index 0000000..e023b0c --- /dev/null +++ b/Mac/English.lproj/Credits.rtf @@ -0,0 +1,30 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1187\cocoasubrtf370 +{\fonttbl\f0\fswiss\fcharset0 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\viewkind0 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720 + +\f0\b\fs24 \cf0 Engineering: +\b0 \ + Jeena Paradies\ +\ + +\b Testing: +\b0 \ + All the early adopters on Tent\ +\ + +\b Documentation: +\b0 \ + http://jabs.nu/bungloo\ +\ + +\b With special thanks to: +\b0 \ + Mom\ +\ + +\b Icon by: +\b0 \ + http://www.fasticon.com\ +} \ No newline at end of file diff --git a/Mac/English.lproj/InfoPlist.strings b/Mac/English.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Mac/English.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Mac/English.lproj/MainMenu.xib b/Mac/English.lproj/MainMenu.xib new file mode 100644 index 0000000..5a0bacb --- /dev/null +++ b/Mac/English.lproj/MainMenu.xib @@ -0,0 +1,3360 @@ + + + + 1080 + 12C60 + 3084 + 1187.34 + 625.00 + + YES + + YES + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + + + YES + 3084 + 2053 + + + + YES + NSButton + NSButtonCell + NSCustomObject + NSImageCell + NSImageView + NSMenu + NSMenuItem + NSProgressIndicator + NSTextField + NSTextFieldCell + NSUserDefaultsController + NSView + NSWindowTemplate + WebView + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + + + PluginDependencyRecalculationVersion + + + + YES + + NSApplication + + + FirstResponder + + + NSApplication + + + AMainMenu + + YES + + + Bungloo + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + Bungloo + + YES + + + About Bungloo + + 2147483647 + + + + + + Check for Updates... + + 2147483647 + + + + + + Preferences... + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + Services + + YES + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide Bungloo + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit Bungloo + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + submenuAction: + + File + + YES + + + New Post + n + 1048576 + 2147483647 + + + + + + Global New Post Key + t + 1835008 + 2147483647 + + + + + + Open Profile ... + u + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Close + w + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Logout + + 2147483647 + + + + + + + + + Edit + + 1048576 + 2147483647 + + + submenuAction: + + Edit + + YES + + + Undo + z + 1048576 + 2147483647 + + + + + + Redo + Z + 1179648 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Cut + x + 1048576 + 2147483647 + + + + + + Copy + c + 1048576 + 2147483647 + + + + + + Paste + v + 1048576 + 2147483647 + + + + + + Paste and Match Style + V + 1572864 + 2147483647 + + + + + + Delete + + 1048576 + 2147483647 + + + + + + Select All + a + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Find + + 1048576 + 2147483647 + + + submenuAction: + + Find + + YES + + + Find… + f + 1048576 + 2147483647 + + + 1 + + + + Find Next + g + 1048576 + 2147483647 + + + 2 + + + + Find Previous + G + 1179648 + 2147483647 + + + 3 + + + + Use Selection for Find + e + 1048576 + 2147483647 + + + 7 + + + + Jump to Selection + j + 1048576 + 2147483647 + + + + + + + + + Spelling and Grammar + + 1048576 + 2147483647 + + + submenuAction: + + Spelling and Grammar + + YES + + + Show Spelling and Grammar + : + 1048576 + 2147483647 + + + + + + Check Document Now + ; + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Check Spelling While Typing + + 1048576 + 2147483647 + + + + + + Check Grammar With Spelling + + 1048576 + 2147483647 + + + + + + Correct Spelling Automatically + + 2147483647 + + + + + + + + + Substitutions + + 1048576 + 2147483647 + + + submenuAction: + + Substitutions + + YES + + + Show Substitutions + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Smart Copy/Paste + f + 1048576 + 2147483647 + + + 1 + + + + Smart Quotes + g + 1048576 + 2147483647 + + + 2 + + + + Smart Dashes + + 2147483647 + + + + + + Smart Links + G + 1179648 + 2147483647 + + + 3 + + + + Text Replacement + + 2147483647 + + + + + + + + + Transformations + + 2147483647 + + + submenuAction: + + Transformations + + YES + + + Make Upper Case + + 2147483647 + + + + + + Make Lower Case + + 2147483647 + + + + + + Capitalize + + 2147483647 + + + + + + + + + Speech + + 1048576 + 2147483647 + + + submenuAction: + + Speech + + YES + + + Start Speaking + + 1048576 + 2147483647 + + + + + + Stop Speaking + + 1048576 + 2147483647 + + + + + + + + + + + + View + + 1048576 + 2147483647 + + + submenuAction: + + View + + YES + + + Show Toolbar + t + 1572864 + 2147483647 + + + + + + Customize Toolbar… + + 1048576 + 2147483647 + + + + + + + + + Window + + 2147483647 + + + submenuAction: + + Window + + YES + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Timeline + 1 + 1048576 + 2147483647 + + + + + + Mentions + 2 + 1048576 + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + + + Bring All to Front + + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 2147483647 + + + submenuAction: + + Help + + YES + + + Bungloo + ? + 1048576 + 2147483647 + + + + + _NSHelpMenu + + + + _NSMainMenu + + + NSFontManager + + + Controller + + + 15 + 2 + {{712, 280}, {397, 581}} + 1685586944 + Bungloo + NSWindow + + + + + 256 + + YES + + + 274 + + YES + + YES + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple URL pasteboard type + Apple Web Archive pasteboard type + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + WebURLsWithTitlesPboardType + public.png + public.url + public.url-name + + + {397, 581} + + + + + + + 13 + + YES + + YES + 13WebKitJavaEnabled + 13WebKitJavaScriptCanOpenWindowsAutomatically + 13WebKitPluginsEnabled + + + YES + + + + + + + NO + YES + + + {397, 581} + + + + + {{0, 0}, {1920, 1178}} + {10000000000000, 10000000000000} + bungloo + YES + + + SUUpdater + + + 15 + 2 + {{1077, 328}, {376, 581}} + 1685586944 + Mentions + NSWindow + + + + + 256 + + YES + + + 274 + + YES + + YES + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple URL pasteboard type + Apple Web Archive pasteboard type + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + WebURLsWithTitlesPboardType + public.png + public.url + public.url-name + + + {376, 581} + + + + + + + 12 + + YES + + YES + 12WebKitJavaEnabled + 12WebKitJavaScriptCanOpenWindowsAutomatically + 12WebKitPluginsEnabled + + + YES + + + + + + + NO + YES + + + {376, 581} + + + + + {{0, 0}, {1920, 1178}} + {10000000000000, 10000000000000} + mentions + YES + + + 15 + 2 + {{1292, 328}, {376, 581}} + 1685586944 + Conversation + NSWindow + + + + + 256 + + YES + + + 274 + + YES + + YES + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple URL pasteboard type + Apple Web Archive pasteboard type + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + WebURLsWithTitlesPboardType + public.png + public.url + public.url-name + + + {376, 581} + + + + + + + NO + YES + + + {376, 581} + + + + + {{0, 0}, {1920, 1178}} + {10000000000000, 10000000000000} + conversation + YES + + + 15 + 2 + {{1292, 328}, {376, 581}} + 1685586944 + Profile + NSWindow + + + + + 256 + + YES + + + 274 + + YES + + YES + Apple HTML pasteboard type + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple URL pasteboard type + Apple Web Archive pasteboard type + NSColor pasteboard type + NSFilenamesPboardType + NSStringPboardType + NeXT RTFD pasteboard type + NeXT Rich Text Format v1.0 pasteboard type + NeXT TIFF v4.0 pasteboard type + WebURLsWithTitlesPboardType + public.png + public.url + public.url-name + + + {376, 581} + + + + + + + NO + YES + + + {376, 581} + + + + + {{0, 0}, {1920, 1178}} + {10000000000000, 10000000000000} + profile + YES + + + 7 + 2 + {{641, 502}, {480, 186}} + 1685586944 + Preferences + NSWindow + + + + + 256 + + YES + + + 268 + + YES + + YES + Apple PDF pasteboard type + Apple PICT pasteboard type + Apple PNG pasteboard type + NSFilenamesPboardType + NeXT Encapsulated PostScript v1.2 pasteboard type + NeXT TIFF v4.0 pasteboard type + + + {{20, 20}, {146, 146}} + + + YES + + 0 + 33554432 + + NSImage + Icon + + 0 + 0 + 0 + YES + + NO + YES + + + + 268 + {{194, 82}, {266, 22}} + + + _NS:9 + YES + + -1804599231 + 272630784 + + + LucidaGrande + 13 + 1044 + + https://example.tent.is + _NS:9 + + YES + + 6 + System + textBackgroundColor + + 3 + MQA + + + + 6 + System + textColor + + 3 + MAA + + + + YES + NSAllRomanInputSourcesLocaleIdentifier + + + NO + + + + 268 + {{191, 112}, {163, 17}} + + + _NS:1535 + YES + + 68157504 + 272630784 + Add your entity to log in: + + _NS:1535 + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + + + NO + + + + 268 + {{391, 46}, {75, 32}} + + _NS:9 + YES + + 67108864 + 134217728 + Login + + _NS:9 + + -2038284288 + 129 + + + 200 + 25 + + NO + + + + 268 + {{373, 55}, {16, 16}} + + + _NS:945 + 28938 + 100 + + + {480, 186} + + _NS:20 + + {{0, 0}, {1920, 1178}} + {10000000000000, 10000000000000} + preferences + YES + + + YES + + + 19 + 2 + {{559, 746}, {373, 116}} + -461896704 + Open Profile ... + NSPanel + + + + + 256 + + YES + + + 268 + {{17, 79}, {192, 17}} + + + _NS:1535 + YES + + 68157504 + 272630784 + Open the profile of the entity: + + _NS:1535 + + + + + NO + + + + 268 + {{20, 49}, {333, 22}} + + + _NS:9 + YES + + -1804599231 + 272630784 + + + https://example.tent.is + _NS:9 + + YES + + + + NO + + + + 268 + {{285, 13}, {74, 32}} + + _NS:9 + YES + + 67108864 + 134217728 + Open + + _NS:9 + + -2038284288 + 129 + + + 200 + 25 + + NO + + + {373, 116} + + _NS:21 + + {{0, 0}, {1920, 1178}} + {10000000000000, 10000000000000} + NO + + + + + YES + + + terminate: + + + + 448 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 564 + + + + performClose: + + + + 193 + + + + toggleContinuousSpellChecking: + + + + 222 + + + + undo: + + + + 223 + + + + copy: + + + + 224 + + + + checkSpelling: + + + + 225 + + + + paste: + + + + 226 + + + + stopSpeaking: + + + + 227 + + + + cut: + + + + 228 + + + + showGuessPanel: + + + + 230 + + + + redo: + + + + 231 + + + + selectAll: + + + + 232 + + + + startSpeaking: + + + + 233 + + + + delete: + + + + 235 + + + + performFindPanelAction: + + + + 241 + + + + centerSelectionInVisibleArea: + + + + 245 + + + + toggleGrammarChecking: + + + + 347 + + + + toggleSmartInsertDelete: + + + + 355 + + + + toggleAutomaticQuoteSubstitution: + + + + 356 + + + + toggleAutomaticLinkDetection: + + + + 357 + + + + runToolbarCustomizationPalette: + + + + 365 + + + + toggleToolbarShown: + + + + 366 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + unhideAllApplications: + + + + 370 + + + + newDocument: + + + + 371 + + + + capitalizeWord: + + + + 454 + + + + lowercaseWord: + + + + 455 + + + + uppercaseWord: + + + + 456 + + + + toggleAutomaticDashSubstitution: + + + + 460 + + + + orderFrontSubstitutionsPanel: + + + + 461 + + + + toggleAutomaticTextReplacement: + + + + 463 + + + + toggleAutomaticSpellingCorrection: + + + + 466 + + + + performFindPanelAction: + + + + 467 + + + + performFindPanelAction: + + + + 468 + + + + performFindPanelAction: + + + + 469 + + + + pasteAsPlainText: + + + + 471 + + + + showHelp: + + + + 494 + + + + newDocument: + + + + 540 + + + + performMiniaturize: + + + + 650 + + + + arrangeInFront: + + + + 651 + + + + performZoom: + + + + 652 + + + + timelineView + + + + 553 + + + + mentionsView + + + + 562 + + + + timelineViewWindow + + + + 565 + + + + mentionsViewWindow + + + + 566 + + + + globalHotkeyMenuItem + + + + 570 + + + + login: + + + + 606 + + + + logout: + + + + 612 + + + + loginViewWindow + + + + 616 + + + + loginActivityIndicator + + + + 622 + + + + conversationView + + + + 632 + + + + conversationViewWindow + + + + 633 + + + + loginEntityTextField + + + + 643 + + + + profileView + + + + 662 + + + + profileViewWindow + + + + 663 + + + + login: + + + + 666 + + + + showProfileTextField + + + + 678 + + + + showProfile: + + + + 680 + + + + showProfile: + + + + 681 + + + + openProfileWindow + + + + 682 + + + + makeKeyAndOrderFront: + + + + 656 + + + + checkForUpdates: + + + + 543 + + + + delegate + + + + 569 + + + + makeKeyAndOrderFront: + + + + 655 + + + + makeKeyAndOrderFront: + + + + 611 + + + + value: values.entity + + + + + + value: values.entity + value + values.entity + 2 + + + 619 + + + + delegate + + + + 631 + + + + delegate + + + + 661 + + + + makeKeyAndOrderFront: + + + + 676 + + + + + YES + + 0 + + YES + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + YES + + + + + + + + + + + 56 + + + YES + + + + + + 217 + + + YES + + + + + + 83 + + + YES + + + + + + 81 + + + YES + + + + + + + + + + + + 72 + + + + + 82 + + + + + 79 + + + + + 205 + + + YES + + + + + + + + + + + + + + + + + + + + 202 + + + + + 198 + + + + + 207 + + + + + 214 + + + + + 199 + + + + + 203 + + + + + 197 + + + + + 206 + + + + + 215 + + + + + 218 + + + YES + + + + + + 216 + + + YES + + + + + + 200 + + + YES + + + + + + + + + + + 219 + + + + + 201 + + + + + 204 + + + + + 220 + + + YES + + + + + + + + + + 213 + + + + + 210 + + + + + 221 + + + + + 208 + + + + + 209 + + + + + 57 + + + YES + + + + + + + + + + + + + + + + 58 + + + + + 134 + + + + + 150 + + + + + 136 + + + + + 144 + + + + + 236 + + + + + 131 + + + YES + + + + + + 149 + + + + + 145 + + + + + 130 + + + + + 295 + + + YES + + + + + + 296 + + + YES + + + + + + + 297 + + + + + 298 + + + + + 211 + + + YES + + + + + + 212 + + + YES + + + + + + + 195 + + + + + 196 + + + + + 346 + + + + + 348 + + + YES + + + + + + 349 + + + YES + + + + + + + + + + + + 350 + + + + + 351 + + + + + 354 + + + + + 419 + + + + + 449 + + + YES + + + + + + 450 + + + YES + + + + + + + + 451 + + + + + 452 + + + + + 453 + + + + + 457 + + + + + 458 + + + + + 459 + + + + + 462 + + + + + 464 + + + + + 465 + + + + + 470 + + + + + 491 + + + YES + + + + + + 492 + + + YES + + + + + + 493 + + + + + 533 + + + + + 535 + + + YES + + + + Timeline + + + 536 + + + YES + + + + + + 537 + + + timeline + + + 541 + + + + + 542 + + + + + 559 + + + YES + + + + Mentions + + + 560 + + + YES + + + + + + 561 + + + + + 592 + + + YES + + + + + + 593 + + + YES + + + + + + + + + + 594 + + + YES + + + + + + 595 + + + + + 596 + + + YES + + + + + + 597 + + + + + 598 + + + YES + + + + + + 599 + + + + + 600 + + + YES + + + + + + 601 + + + + + 602 + + + + + 603 + + + + + 610 + + + + + 613 + + + + + 620 + + + + + 73 + + + + + 628 + + + YES + + + + Conversation + + + 629 + + + YES + + + + + + 630 + + + + + 644 + + + YES + + + + + + 645 + + + YES + + + + + + + + + + + + 646 + + + + + 647 + + + + + 648 + + + + + 649 + + + + + 653 + + + + + 654 + + + + + 657 + + + + + 658 + + + YES + + + + Profile + + + 659 + + + YES + + + + + + 660 + + + + + 667 + + + + + 668 + + + YES + + + + + + 669 + + + YES + + + + + + + + 670 + + + YES + + + + + + 671 + + + + + 672 + + + YES + + + + + + 673 + + + + + 674 + + + YES + + + + + + 675 + + + + + + + YES + + YES + -1.IBPluginDependency + -2.IBPluginDependency + -3.IBPluginDependency + 130.IBPluginDependency + 131.IBPluginDependency + 134.IBPluginDependency + 136.IBPluginDependency + 144.IBPluginDependency + 145.IBPluginDependency + 149.IBPluginDependency + 150.IBPluginDependency + 195.IBPluginDependency + 196.IBPluginDependency + 197.IBPluginDependency + 198.IBPluginDependency + 199.IBPluginDependency + 200.IBPluginDependency + 201.IBPluginDependency + 202.IBPluginDependency + 203.IBPluginDependency + 204.IBPluginDependency + 205.IBPluginDependency + 206.IBPluginDependency + 207.IBPluginDependency + 208.IBPluginDependency + 209.IBPluginDependency + 210.IBPluginDependency + 211.IBPluginDependency + 212.IBPluginDependency + 213.IBPluginDependency + 214.IBPluginDependency + 215.IBPluginDependency + 216.IBPluginDependency + 217.IBPluginDependency + 218.IBPluginDependency + 219.IBPluginDependency + 220.IBPluginDependency + 221.IBPluginDependency + 236.IBPluginDependency + 29.IBPluginDependency + 295.IBPluginDependency + 296.IBPluginDependency + 297.IBPluginDependency + 298.IBPluginDependency + 346.IBPluginDependency + 348.IBPluginDependency + 349.IBPluginDependency + 350.IBPluginDependency + 351.IBPluginDependency + 354.IBPluginDependency + 419.IBPluginDependency + 449.IBPluginDependency + 450.IBPluginDependency + 451.IBPluginDependency + 452.IBPluginDependency + 453.IBPluginDependency + 457.IBPluginDependency + 458.IBPluginDependency + 459.IBPluginDependency + 462.IBPluginDependency + 464.IBPluginDependency + 465.IBPluginDependency + 470.IBPluginDependency + 491.IBPluginDependency + 492.IBPluginDependency + 493.IBPluginDependency + 533.IBPluginDependency + 535.IBPluginDependency + 535.IBWindowTemplateEditedContentRect + 535.NSWindowTemplate.visibleAtLaunch + 536.IBPluginDependency + 537.IBPluginDependency + 541.IBPluginDependency + 542.IBPluginDependency + 559.IBPluginDependency + 559.IBWindowTemplateEditedContentRect + 559.NSWindowTemplate.visibleAtLaunch + 56.IBPluginDependency + 560.IBPluginDependency + 561.IBPluginDependency + 57.IBPluginDependency + 58.IBPluginDependency + 592.IBPluginDependency + 592.NSWindowTemplate.visibleAtLaunch + 593.IBPluginDependency + 594.IBPluginDependency + 595.IBPluginDependency + 596.IBPluginDependency + 597.IBPluginDependency + 598.IBPluginDependency + 599.IBPluginDependency + 600.IBPluginDependency + 601.IBPluginDependency + 602.IBPluginDependency + 603.IBPluginDependency + 610.IBPluginDependency + 613.IBPluginDependency + 620.IBPluginDependency + 628.IBPluginDependency + 628.IBWindowTemplateEditedContentRect + 628.NSWindowTemplate.visibleAtLaunch + 629.IBPluginDependency + 630.IBPluginDependency + 644.IBPluginDependency + 645.IBPluginDependency + 646.IBPluginDependency + 647.IBPluginDependency + 648.IBPluginDependency + 649.IBPluginDependency + 653.IBPluginDependency + 654.IBPluginDependency + 657.IBPluginDependency + 658.IBPluginDependency + 658.IBWindowTemplateEditedContentRect + 658.NSWindowTemplate.visibleAtLaunch + 659.IBPluginDependency + 660.IBPluginDependency + 667.IBPluginDependency + 668.IBPluginDependency + 668.NSWindowTemplate.visibleAtLaunch + 669.IBPluginDependency + 670.IBPluginDependency + 671.IBPluginDependency + 672.IBPluginDependency + 673.IBPluginDependency + 674.IBPluginDependency + 675.IBPluginDependency + 72.IBPluginDependency + 73.IBPluginDependency + 79.IBPluginDependency + 81.IBPluginDependency + 82.IBPluginDependency + 83.IBPluginDependency + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{202, 175}, {397, 581}} + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{344, 175}, {376, 581}} + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{344, 175}, {376, 581}} + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{344, 175}, {376, 581}} + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.WebKitIBPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + YES + + + + + + YES + + + + + 682 + + + + YES + + Controller + NSObject + + YES + + YES + clearCache: + login: + logout: + showProfile: + + + YES + id + id + id + id + + + + YES + + YES + clearCache: + login: + logout: + showProfile: + + + YES + + clearCache: + id + + + login: + id + + + logout: + id + + + showProfile: + id + + + + + YES + + YES + conversationView + conversationViewWindow + globalHotkeyMenuItem + loginActivityIndicator + loginEntityTextField + loginViewWindow + logoLayer + mentionsView + mentionsViewWindow + openProfileWindow + profileView + profileViewWindow + showProfileTextField + timelineView + timelineViewWindow + viewDelegate + + + YES + WebView + NSWindow + NSMenuItem + NSProgressIndicator + NSTextField + NSWindow + NSImageView + WebView + NSWindow + NSPanel + WebView + NSWindow + NSTextField + WebView + NSWindow + ViewDelegate + + + + YES + + YES + conversationView + conversationViewWindow + globalHotkeyMenuItem + loginActivityIndicator + loginEntityTextField + loginViewWindow + logoLayer + mentionsView + mentionsViewWindow + openProfileWindow + profileView + profileViewWindow + showProfileTextField + timelineView + timelineViewWindow + viewDelegate + + + YES + + conversationView + WebView + + + conversationViewWindow + NSWindow + + + globalHotkeyMenuItem + NSMenuItem + + + loginActivityIndicator + NSProgressIndicator + + + loginEntityTextField + NSTextField + + + loginViewWindow + NSWindow + + + logoLayer + NSImageView + + + mentionsView + WebView + + + mentionsViewWindow + NSWindow + + + openProfileWindow + NSPanel + + + profileView + WebView + + + profileViewWindow + NSWindow + + + showProfileTextField + NSTextField + + + timelineView + WebView + + + timelineViewWindow + NSWindow + + + viewDelegate + ViewDelegate + + + + + IBProjectSource + ./Classes/Controller.h + + + + SUUpdater + NSObject + + checkForUpdates: + id + + + checkForUpdates: + + checkForUpdates: + id + + + + delegate + id + + + delegate + + delegate + id + + + + IBProjectSource + ./Classes/SUUpdater.h + + + + ViewDelegate + NSObject + + IBProjectSource + ./Classes/ViewDelegate.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + 3 + + YES + + YES + Icon + NSMenuCheckmark + NSMenuMixedState + + + YES + {256, 256} + {11, 11} + {10, 3} + + + + diff --git a/Mac/English.lproj/NewMessageWindow.xib b/Mac/English.lproj/NewMessageWindow.xib new file mode 100644 index 0000000..c1aacae --- /dev/null +++ b/Mac/English.lproj/NewMessageWindow.xib @@ -0,0 +1,834 @@ + + + + 1080 + 12C60 + 2844 + 1187.34 + 625.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 2844 + + + YES + NSButton + NSButtonCell + NSCustomObject + NSMenu + NSMenuItem + NSTextField + NSTextFieldCell + NSView + NSWindowTemplate + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + YES + + NewMessageWindow + + + FirstResponder + + + 15 + 2 + {{133, 535}, {299, 113}} + 1886913536 + New Post + NSWindow + View + + {94, 86} + + + 256 + + YES + + + 274 + {{0, 22}, {299, 91}} + + + + YES + + -1809842175 + 268468224 + + + LucidaGrande + 13 + 1044 + + + YES + + 6 + System + textBackgroundColor + + 3 + MQA + + + + 6 + System + textColor + + 3 + MAA + + + + NO + + + + 289 + {{215, 3}, {38, 17}} + + + + YES + + 68157504 + 71304192 + 256 + + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + + + NO + + + + 292 + {{2, 0}, {18, 19}} + + + + _NS:9 + YES + + 67108864 + 134217728 + + + LucidaGrande-Bold + 12 + 16 + + _NS:9 + + 113524736 + 268435629 + + NSImage + NSAddTemplate + + + + + 200 + 25 + + NO + + + + 289 + {{258, 2}, {38, 16}} + + + + _NS:9 + YES + + -2080374784 + 134217728 + ⌘↩ + + LucidaGrande-Bold + 11 + 3357 + + _NS:9 + + -2033434624 + 268435623 + + DQ + 400 + 75 + + NO + + + + 292 + {{20, 1}, {19, 19}} + + + + _NS:9 + YES + + 67108864 + 134217728 + + + _NS:9 + + 113524736 + 268435629 + + NSImage + NSLockUnlockedTemplate + + + p + 200 + 25 + + NO + + + {299, 113} + + + + + {{0, 0}, {2560, 1418}} + {94, 108} + {10000000000000, 10000000000000} + newPost + NO + 22 + YES + + + NSApplication + + + + + YES + + + Add current location + + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + + + + Add photo + + 2147483647 + + + + + + + + 268 + {29, 15} + _NS:9 + YES + + 67108864 + 134217728 + + + _NS:9 + + -2030813184 + 39 + + 549650432 + {1, 1} + + YES + + YES + + + + TU0AKgAAAAoAAAAOAQAAAwAAAAEAAQAAAQEAAwAAAAEAAQAAAQIAAwAAAAIACAAIAQMAAwAAAAEAAQAA +AQYAAwAAAAEAAQAAAREABAAAAAEAAAAIARIAAwAAAAEAAQAAARUAAwAAAAEAAgAAARYAAwAAAAEAAQAA +ARcABAAAAAEAAAACARwAAwAAAAEAAQAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABh3MABwAAB7gAAAC4 +AAAAAAAAB7hhcHBsAiAAAG1udHJHUkFZWFlaIAfQAAIADgAMAAAAAGFjc3BBUFBMAAAAAG5vbmUAAAAA +AAAAAAAAAAAAAAAAAAD21gABAAAAANMtYXBwbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAABWRlc2MAAADAAAAAb2RzY20AAAEwAAAGLGNwcnQAAAdcAAAAOHd0cHQAAAeU +AAAAFGtUUkMAAAeoAAAADmRlc2MAAAAAAAAAFUdlbmVyaWMgR3JheSBQcm9maWxlAAAAAAAAAAAAAAAV +R2VuZXJpYyBHcmF5IFByb2ZpbGUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAABtbHVjAAAAAAAAAB4AAAAMc2tTSwAAACoAAAF4aHJIUgAAADoAAAGiY2FFUwAAACwAAAHc +cHRCUgAAACoAAAIIdWtVQQAAACwAAAIyZnJGVQAAACoAAAJeemhUVwAAABAAAAKIaXRJVAAAAC4AAAKY +bmJOTwAAACwAAALGa29LUgAAABgAAALyY3NDWgAAACQAAAMKaGVJTAAAACAAAAMuZGVERQAAADoAAANO +aHVIVQAAAC4AAAOIc3ZTRQAAAC4AAAO2emhDTgAAABAAAAPkamFKUAAAABYAAAP0cm9STwAAACIAAAQK +ZWxHUgAAACQAAAQscHRQTwAAADgAAARQbmxOTAAAACoAAASIZXNFUwAAACgAAASydGhUSAAAACQAAATa +dHJUUgAAACIAAAT+ZmlGSQAAACwAAAUgcGxQTAAAADYAAAVMcnVSVQAAACYAAAWCYXJFRwAAACgAAAWo +ZW5VUwAAACgAAAXQZGFESwAAADQAAAX4AFYBYQBlAG8AYgBlAGMAbgD9ACAAcwBpAHYA/QAgAHAAcgBv +AGYAaQBsAEcAZQBuAGUAcgBpAQ0AawBpACAAcAByAG8AZgBpAGwAIABzAGkAdgBpAGgAIAB0AG8AbgBv +AHYAYQBQAGUAcgBmAGkAbAAgAGQAZQAgAGcAcgBpAHMAIABnAGUAbgDoAHIAaQBjAFAAZQByAGYAaQBs +ACAAQwBpAG4AegBhACAARwBlAG4A6QByAGkAYwBvBBcEMAQzBDAEOwRMBD0EOAQ5ACAEPwRABD4ERAQw +BDkEOwAgAEcAcgBhAHkAUAByAG8AZgBpAGwAIABnAOkAbgDpAHIAaQBxAHUAZQAgAGcAcgBpAHOQGnUo +cHCWjoJyX2ljz4/wAFAAcgBvAGYAaQBsAG8AIABnAHIAaQBnAGkAbwAgAGcAZQBuAGUAcgBpAGMAbwBH +AGUAbgBlAHIAaQBzAGsAIABnAHIA5QB0AG8AbgBlAHAAcgBvAGYAaQBsx3y8GAAgAEcAcgBhAHkAINUE +uFzTDMd8AE8AYgBlAGMAbgD9ACABYQBlAGQA/QAgAHAAcgBvAGYAaQBsBeQF6AXVBeQF2QXcACAARwBy +AGEAeQAgBdsF3AXcBdkAQQBsAGwAZwBlAG0AZQBpAG4AZQBzACAARwByAGEAdQBzAHQAdQBmAGUAbgAt +AFAAcgBvAGYAaQBsAMEAbAB0AGEAbADhAG4AbwBzACAAcwB6APwAcgBrAGUAIABwAHIAbwBmAGkAbABH +AGUAbgBlAHIAaQBzAGsAIABnAHIA5QBzAGsAYQBsAGUAcAByAG8AZgBpAGxmbpAacHBepmPPj/Blh072 +TgCCLDCwMOwwpDDXMO0w1TChMKQw6wBQAHIAbwBmAGkAbAAgAGcAcgBpACAAZwBlAG4AZQByAGkDkwO1 +A70DuQO6A8wAIAPAA8EDvwPGA68DuwAgA7MDugPBA7kAUABlAHIAZgBpAGwAIABnAGUAbgDpAHIAaQBj +AG8AIABkAGUAIABjAGkAbgB6AGUAbgB0AG8AcwBBAGwAZwBlAG0AZQBlAG4AIABnAHIAaQBqAHMAcABy +AG8AZgBpAGUAbABQAGUAcgBmAGkAbAAgAGcAcgBpAHMAIABnAGUAbgDpAHIAaQBjAG8OQg4bDiMORA4f +DiUOTA4qDjUOQA4XDjIOFw4xDkgOJw5EDhsARwBlAG4AZQBsACAARwByAGkAIABQAHIAbwBmAGkAbABp +AFkAbABlAGkAbgBlAG4AIABoAGEAcgBtAGEAYQBwAHIAbwBmAGkAaQBsAGkAVQBuAGkAdwBlAHIAcwBh +AGwAbgB5ACAAcAByAG8AZgBpAGwAIABzAHoAYQByAG8BWwBjAGkEHgQxBEkEOAQ5ACAEQQQ1BEAESwQ5 +ACAEPwRABD4ERAQ4BDsETAZFBkQGQQAgBioGOQYxBkoGQQAgAEcAcgBhAHkAIAYnBkQGOQYnBkUARwBl +AG4AZQByAGkAYwAgAEcAcgBhAHkAIABQAHIAbwBmAGkAbABlAEcAZQBuAGUAcgBlAGwAIABnAHIA5QB0 +AG8AbgBlAGIAZQBzAGsAcgBpAHYAZQBsAHMAZXRleHQAAAAAQ29weXJpZ2h0IDIwMDcgQXBwbGUgSW5j +LiwgYWxsIHJpZ2h0cyByZXNlcnZlZC4AWFlaIAAAAAAAAPNRAAEAAAABFsxjdXJ2AAAAAAAAAAEBzQAA +A + + + + + + 3 + MCAwAA + + + + + 200 + 25 + + NO + + + + + YES + + + window + + + + 18 + + + + textField + + + + 100034 + + + + counter + + + + 100038 + + + + addMenu + + + + 100048 + + + + addCurrentLocation: + + + + 100049 + + + + openAddMenu: + + + + 100053 + + + + addMenuButton + + + + 100054 + + + + sendPost: + + + + 100068 + + + + sendPostButtonPressed: + + + + 100070 + + + + togglePrivate: + + + + 100076 + + + + togglePrivateButton + + + + 100080 + + + + addImage: + + + + 100083 + + + + delegate + + + + 100035 + + + + menu + + + + 100045 + + + + + YES + + 0 + + YES + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + 5 + + + YES + + + + Window + + + 6 + + + YES + + + + + + + + + + -3 + + + Application + + + 100028 + + + YES + + + + + + 100029 + + + + + 100036 + + + YES + + + + + + 100037 + + + + + 100039 + + + YES + + + + + + 100040 + + + + + 100041 + + + YES + + + + + + + 100043 + + + + + 100059 + + + YES + + + + + + 100060 + + + + + 100065 + + + YES + + + + + + 100066 + + + + + 100074 + + + YES + + + + + + 100075 + + + + + 100081 + + + + + + + YES + + YES + -1.IBPluginDependency + -2.IBPluginDependency + -3.IBPluginDependency + 100028.IBPluginDependency + 100029.IBPluginDependency + 100036.IBPluginDependency + 100037.IBPluginDependency + 100039.IBPluginDependency + 100040.IBPluginDependency + 100041.IBPluginDependency + 100043.IBPluginDependency + 100059.IBPluginDependency + 100060.IBPluginDependency + 100065.IBPluginDependency + 100066.IBPluginDependency + 100074.IBPluginDependency + 100075.IBPluginDependency + 100081.IBPluginDependency + 5.IBPluginDependency + 5.IBWindowTemplateEditedContentRect + 6.IBPluginDependency + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{127, 736}, {299, 113}} + com.apple.InterfaceBuilder.CocoaPlugin + + + + YES + + + + + + YES + + + + + 100083 + + + + YES + + NewMessageWindow + NSDocument + + YES + + YES + addCurrentLocation: + addImage: + openAddMenu: + sendPost: + sendPostButtonPressed: + togglePrivate: + + + YES + id + id + id + NSControl + id + id + + + + YES + + YES + addCurrentLocation: + addImage: + openAddMenu: + sendPost: + sendPostButtonPressed: + togglePrivate: + + + YES + + addCurrentLocation: + id + + + addImage: + id + + + openAddMenu: + id + + + sendPost: + NSControl + + + sendPostButtonPressed: + id + + + togglePrivate: + id + + + + + YES + + YES + addMenu + addMenuButton + counter + textField + togglePrivateButton + + + YES + NSMenu + NSButton + NSTextField + NSTextField + NSButton + + + + YES + + YES + addMenu + addMenuButton + counter + textField + togglePrivateButton + + + YES + + addMenu + NSMenu + + + addMenuButton + NSButton + + + counter + NSTextField + + + textField + NSTextField + + + togglePrivateButton + NSButton + + + + + IBProjectSource + ./Classes/NewMessageWindow.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + 3 + + YES + + YES + NSAddTemplate + NSLockUnlockedTemplate + NSMenuCheckmark + NSMenuMixedState + + + YES + {8, 8} + {9, 12} + {11, 11} + {10, 3} + + + + diff --git a/Mac/Growl Registration Ticket.growlRegDict b/Mac/Growl Registration Ticket.growlRegDict new file mode 100644 index 0000000..b7c02c5 --- /dev/null +++ b/Mac/Growl Registration Ticket.growlRegDict @@ -0,0 +1,17 @@ + + + + + TicketVersion + 1 + DefaultNotifications + + Mention + + AllNotifications + + Mention + Status + + + diff --git a/Mac/Growl.framework/Growl b/Mac/Growl.framework/Growl new file mode 120000 index 0000000..85956e2 --- /dev/null +++ b/Mac/Growl.framework/Growl @@ -0,0 +1 @@ +Versions/Current/Growl \ No newline at end of file diff --git a/Mac/Growl.framework/Headers b/Mac/Growl.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/Mac/Growl.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/Mac/Growl.framework/Resources b/Mac/Growl.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Mac/Growl.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Mac/Growl.framework/Versions/A/Growl b/Mac/Growl.framework/Versions/A/Growl new file mode 100755 index 0000000..f61df83 Binary files /dev/null and b/Mac/Growl.framework/Versions/A/Growl differ diff --git a/Mac/Growl.framework/Versions/A/Headers/Growl.h b/Mac/Growl.framework/Versions/A/Headers/Growl.h new file mode 100644 index 0000000..7b1a324 --- /dev/null +++ b/Mac/Growl.framework/Versions/A/Headers/Growl.h @@ -0,0 +1,5 @@ +#include + +#ifdef __OBJC__ +# include +#endif diff --git a/Mac/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h b/Mac/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h new file mode 100644 index 0000000..6ad38f9 --- /dev/null +++ b/Mac/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h @@ -0,0 +1,567 @@ +// +// GrowlApplicationBridge.h +// Growl +// +// Created by Evan Schoenberg on Wed Jun 16 2004. +// Copyright 2004-2006 The Growl Project. All rights reserved. +// + +/*! + * @header GrowlApplicationBridge.h + * @abstract Defines the GrowlApplicationBridge class. + * @discussion This header defines the GrowlApplicationBridge class as well as + * the GROWL_PREFPANE_BUNDLE_IDENTIFIER constant. + */ + +#ifndef __GrowlApplicationBridge_h__ +#define __GrowlApplicationBridge_h__ + +#import +#import +#import + +//Forward declarations +@protocol GrowlApplicationBridgeDelegate; + +//------------------------------------------------------------------------------ +#pragma mark - + +/*! + * @class GrowlApplicationBridge + * @abstract A class used to interface with Growl. + * @discussion This class provides a means to interface with Growl. + * + * Currently it provides a way to detect if Growl is installed and launch the + * GrowlHelperApp if it's not already running. + */ +@interface GrowlApplicationBridge : NSObject { + +} + +/*! + * @method isGrowlInstalled + * @abstract Detects whether Growl is installed. + * @discussion Determines if the Growl prefpane and its helper app are installed. + * @result this method will forever return YES. + */ ++ (BOOL) isGrowlInstalled __attribute__((deprecated)); + +/*! + * @method isGrowlRunning + * @abstract Detects whether GrowlHelperApp is currently running. + * @discussion Cycles through the process list to find whether GrowlHelperApp is running and returns its findings. + * @result Returns YES if GrowlHelperApp is running, NO otherwise. + */ ++ (BOOL) isGrowlRunning; + + +/*! + * @method isMistEnabled + * @abstract Gives the caller a fairly good indication of whether or not built-in notifications(Mist) will be used. + * @discussion since this call makes use of isGrowlRunning it is entirely possible for this value to change between call and + * executing a notification dispatch + * @result Returns YES if Growl isn't reachable and the developer has not opted-out of + * Mist and the user hasn't set the global mist enable key to false. + */ ++ (BOOL)isMistEnabled; + +/*! + * @method setShouldUseBuiltInNotifications + * @abstract opt-out mechanism for the mist notification style in the event growl can't be reached. + * @discussion if growl is unavailable due to not being installed or as a result of being turned off then + * this option can enable/disable a built-in fire and forget display style + * @param should Specifies whether or not the developer wants to opt-in (default) or opt out + * of the built-in Mist style in the event Growl is unreachable. + */ ++ (void)setShouldUseBuiltInNotifications:(BOOL)should; + +/*! + * @method shouldUseBuiltInNotifications + * @abstract returns the current opt-in state of the framework's use of the Mist display style. + * @result Returns NO if the developer opt-ed out of Mist, the default value is YES. + */ ++ (BOOL)shouldUseBuiltInNotifications; + +#pragma mark - + +/*! + * @method setGrowlDelegate: + * @abstract Set the object which will be responsible for providing and receiving Growl information. + * @discussion This must be called before using GrowlApplicationBridge. + * + * The methods in the GrowlApplicationBridgeDelegate protocol are required + * and return the basic information needed to register with Growl. + * + * The methods in the GrowlApplicationBridgeDelegate_InformalProtocol + * informal protocol are individually optional. They provide a greater + * degree of interaction between the application and growl such as informing + * the application when one of its Growl notifications is clicked by the user. + * + * The methods in the GrowlApplicationBridgeDelegate_Installation_InformalProtocol + * informal protocol are individually optional and are only applicable when + * using the Growl-WithInstaller.framework which allows for automated Growl + * installation. + * + * When this method is called, data will be collected from inDelegate, Growl + * will be launched if it is not already running, and the application will be + * registered with Growl. + * + * If using the Growl-WithInstaller framework, if Growl is already installed + * but this copy of the framework has an updated version of Growl, the user + * will be prompted to update automatically. + * + * @param inDelegate The delegate for the GrowlApplicationBridge. It must conform to the GrowlApplicationBridgeDelegate protocol. + */ ++ (void) setGrowlDelegate:(id)inDelegate; + +/*! + * @method growlDelegate + * @abstract Return the object responsible for providing and receiving Growl information. + * @discussion See setGrowlDelegate: for details. + * @result The Growl delegate. + */ ++ (id) growlDelegate; + +#pragma mark - + +/*! + * @method notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext: + * @abstract Send a Growl notification. + * @discussion This is the preferred means for sending a Growl notification. + * The notification name and at least one of the title and description are + * required (all three are preferred). All other parameters may be + * nil (or 0 or NO as appropriate) to accept default values. + * + * If using the Growl-WithInstaller framework, if Growl is not installed the + * user will be prompted to install Growl. If the user cancels, this method + * will have no effect until the next application session, at which time when + * it is called the user will be prompted again. The user is also given the + * option to not be prompted again. If the user does choose to install Growl, + * the requested notification will be displayed once Growl is installed and + * running. + * + * @param title The title of the notification displayed to the user. + * @param description The full description of the notification displayed to the user. + * @param notifName The internal name of the notification. Should be human-readable, as it will be displayed in the Growl preference pane. + * @param iconData NSData object to show with the notification as its icon. If nil, the application's icon will be used instead. + * @param priority The priority of the notification. The default value is 0; positive values are higher priority and negative values are lower priority. Not all Growl displays support priority. + * @param isSticky If YES, the notification will remain on screen until clicked. Not all Growl displays support sticky notifications. + * @param clickContext A context passed back to the Growl delegate if it implements -(void)growlNotificationWasClicked: and the notification is clicked. Not all display plugins support clicking. The clickContext must be plist-encodable (completely of NSString, NSArray, NSNumber, NSDictionary, and NSData types). + */ ++ (void) notifyWithTitle:(NSString *)title + description:(NSString *)description + notificationName:(NSString *)notifName + iconData:(NSData *)iconData + priority:(signed int)priority + isSticky:(BOOL)isSticky + clickContext:(id)clickContext; + +/*! + * @method notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:identifier: + * @abstract Send a Growl notification. + * @discussion This is the preferred means for sending a Growl notification. + * The notification name and at least one of the title and description are + * required (all three are preferred). All other parameters may be + * nil (or 0 or NO as appropriate) to accept default values. + * + * If using the Growl-WithInstaller framework, if Growl is not installed the + * user will be prompted to install Growl. If the user cancels, this method + * will have no effect until the next application session, at which time when + * it is called the user will be prompted again. The user is also given the + * option to not be prompted again. If the user does choose to install Growl, + * the requested notification will be displayed once Growl is installed and + * running. + * + * @param title The title of the notification displayed to the user. + * @param description The full description of the notification displayed to the user. + * @param notifName The internal name of the notification. Should be human-readable, as it will be displayed in the Growl preference pane. + * @param iconData NSData object to show with the notification as its icon. If nil, the application's icon will be used instead. + * @param priority The priority of the notification. The default value is 0; positive values are higher priority and negative values are lower priority. Not all Growl displays support priority. + * @param isSticky If YES, the notification will remain on screen until clicked. Not all Growl displays support sticky notifications. + * @param clickContext A context passed back to the Growl delegate if it implements -(void)growlNotificationWasClicked: and the notification is clicked. Not all display plugins support clicking. The clickContext must be plist-encodable (completely of NSString, NSArray, NSNumber, NSDictionary, and NSData types). + * @param identifier An identifier for this notification. Notifications with equal identifiers are coalesced. + */ ++ (void) notifyWithTitle:(NSString *)title + description:(NSString *)description + notificationName:(NSString *)notifName + iconData:(NSData *)iconData + priority:(signed int)priority + isSticky:(BOOL)isSticky + clickContext:(id)clickContext + identifier:(NSString *)identifier; + +/*! @method notifyWithDictionary: + * @abstract Notifies using a userInfo dictionary suitable for passing to + * NSDistributedNotificationCenter. + * @param userInfo The dictionary to notify with. + * @discussion Before Growl 0.6, your application would have posted + * notifications using NSDistributedNotificationCenter by + * creating a userInfo dictionary with the notification data. This had the + * advantage of allowing you to add other data to the dictionary for programs + * besides Growl that might be listening. + * + * This method allows you to use such dictionaries without being restricted + * to using NSDistributedNotificationCenter. The keys for this dictionary + * can be found in GrowlDefines.h. + */ ++ (void) notifyWithDictionary:(NSDictionary *)userInfo; + +#pragma mark - + +/*! @method registerWithDictionary: + * @abstract Register your application with Growl without setting a delegate. + * @discussion When you call this method with a dictionary, + * GrowlApplicationBridge registers your application using that dictionary. + * If you pass nil, GrowlApplicationBridge will ask the delegate + * (if there is one) for a dictionary, and if that doesn't work, it will look + * in your application's bundle for an auto-discoverable plist. + * (XXX refer to more information on that) + * + * If you pass a dictionary to this method, it must include the + * GROWL_APP_NAME key, unless a delegate is set. + * + * This method is mainly an alternative to the delegate system introduced + * with Growl 0.6. Without a delegate, you cannot receive callbacks such as + * -growlIsReady (since they are sent to the delegate). You can, + * however, set a delegate after registering without one. + * + * This method was introduced in Growl.framework 0.7. + */ ++ (BOOL) registerWithDictionary:(NSDictionary *)regDict; + +/*! @method reregisterGrowlNotifications + * @abstract Reregister the notifications for this application. + * @discussion This method does not normally need to be called. If your + * application changes what notifications it is registering with Growl, call + * this method to have the Growl delegate's + * -registrationDictionaryForGrowl method called again and the + * Growl registration information updated. + * + * This method is now implemented using -registerWithDictionary:. + */ ++ (void) reregisterGrowlNotifications; + +#pragma mark - + +/*! @method setWillRegisterWhenGrowlIsReady: + * @abstract Tells GrowlApplicationBridge to register with Growl when Growl + * launches (or not). + * @discussion When Growl has started listening for notifications, it posts a + * GROWL_IS_READY notification on the Distributed Notification + * Center. GrowlApplicationBridge listens for this notification, using it to + * perform various tasks (such as calling your delegate's + * -growlIsReady method, if it has one). If this method is + * called with YES, one of those tasks will be to reregister + * with Growl (in the manner of -reregisterGrowlNotifications). + * + * This attribute is automatically set back to NO (the default) + * after every GROWL_IS_READY notification. + * @param flag YES if you want GrowlApplicationBridge to register with + * Growl when next it is ready; NO if not. + */ ++ (void) setWillRegisterWhenGrowlIsReady:(BOOL)flag; + +/*! @method willRegisterWhenGrowlIsReady + * @abstract Reports whether GrowlApplicationBridge will register with Growl + * when Growl next launches. + * @result YES if GrowlApplicationBridge will register with Growl + * when next it posts GROWL_IS_READY; NO if not. + */ ++ (BOOL) willRegisterWhenGrowlIsReady; + +#pragma mark - + +/*! @method registrationDictionaryFromDelegate + * @abstract Asks the delegate for a registration dictionary. + * @discussion If no delegate is set, or if the delegate's + * -registrationDictionaryForGrowl method returns + * nil, this method returns nil. + * + * This method does not attempt to clean up the dictionary in any way - for + * example, if it is missing the GROWL_APP_NAME key, the result + * will be missing it too. Use +[GrowlApplicationBridge + * registrationDictionaryByFillingInDictionary:] or + * +[GrowlApplicationBridge + * registrationDictionaryByFillingInDictionary:restrictToKeys:] to try + * to fill in missing keys. + * + * This method was introduced in Growl.framework 0.7. + * @result A registration dictionary. + */ ++ (NSDictionary *) registrationDictionaryFromDelegate; + +/*! @method registrationDictionaryFromBundle: + * @abstract Looks in a bundle for a registration dictionary. + * @discussion This method looks in a bundle for an auto-discoverable + * registration dictionary file using -[NSBundle + * pathForResource:ofType:]. If it finds one, it loads the file using + * +[NSDictionary dictionaryWithContentsOfFile:] and returns the + * result. + * + * If you pass nil as the bundle, the main bundle is examined. + * + * This method does not attempt to clean up the dictionary in any way - for + * example, if it is missing the GROWL_APP_NAME key, the result + * will be missing it too. Use +[GrowlApplicationBridge + * registrationDictionaryByFillingInDictionary:] or + * +[GrowlApplicationBridge + * registrationDictionaryByFillingInDictionary:restrictToKeys:] to try + * to fill in missing keys. + * + * This method was introduced in Growl.framework 0.7. + * @result A registration dictionary. + */ ++ (NSDictionary *) registrationDictionaryFromBundle:(NSBundle *)bundle; + +/*! @method bestRegistrationDictionary + * @abstract Obtains a registration dictionary, filled out to the best of + * GrowlApplicationBridge's knowledge. + * @discussion This method creates a registration dictionary as best + * GrowlApplicationBridge knows how. + * + * First, GrowlApplicationBridge contacts the Growl delegate (if there is + * one) and gets the registration dictionary from that. If no such dictionary + * was obtained, GrowlApplicationBridge looks in your application's main + * bundle for an auto-discoverable registration dictionary file. If that + * doesn't exist either, this method returns nil. + * + * Second, GrowlApplicationBridge calls + * +registrationDictionaryByFillingInDictionary: with whatever + * dictionary was obtained. The result of that method is the result of this + * method. + * + * GrowlApplicationBridge uses this method when you call + * +setGrowlDelegate:, or when you call + * +registerWithDictionary: with nil. + * + * This method was introduced in Growl.framework 0.7. + * @result A registration dictionary. + */ ++ (NSDictionary *) bestRegistrationDictionary; + +#pragma mark - + +/*! @method registrationDictionaryByFillingInDictionary: + * @abstract Tries to fill in missing keys in a registration dictionary. + * @discussion This method examines the passed-in dictionary for missing keys, + * and tries to work out correct values for them. As of 0.7, it uses: + * + * Key Value + * --- ----- + * GROWL_APP_NAME CFBundleExecutableName + * GROWL_APP_ICON_DATA The data of the icon of the application. + * GROWL_APP_LOCATION The location of the application. + * GROWL_NOTIFICATIONS_DEFAULT GROWL_NOTIFICATIONS_ALL + * + * Keys are only filled in if missing; if a key is present in the dictionary, + * its value will not be changed. + * + * This method was introduced in Growl.framework 0.7. + * @param regDict The dictionary to fill in. + * @result The dictionary with the keys filled in. This is an autoreleased + * copy of regDict. + */ ++ (NSDictionary *) registrationDictionaryByFillingInDictionary:(NSDictionary *)regDict; + +/*! @method registrationDictionaryByFillingInDictionary:restrictToKeys: + * @abstract Tries to fill in missing keys in a registration dictionary. + * @discussion This method examines the passed-in dictionary for missing keys, + * and tries to work out correct values for them. As of 0.7, it uses: + * + * Key Value + * --- ----- + * GROWL_APP_NAME CFBundleExecutableName + * GROWL_APP_ICON_DATA The data of the icon of the application. + * GROWL_APP_LOCATION The location of the application. + * GROWL_NOTIFICATIONS_DEFAULT GROWL_NOTIFICATIONS_ALL + * + * Only those keys that are listed in keys will be filled in. + * Other missing keys are ignored. Also, keys are only filled in if missing; + * if a key is present in the dictionary, its value will not be changed. + * + * This method was introduced in Growl.framework 0.7. + * @param regDict The dictionary to fill in. + * @param keys The keys to fill in. If nil, any missing keys are filled in. + * @result The dictionary with the keys filled in. This is an autoreleased + * copy of regDict. + */ ++ (NSDictionary *) registrationDictionaryByFillingInDictionary:(NSDictionary *)regDict restrictToKeys:(NSSet *)keys; + +/*! @brief Tries to fill in missing keys in a notification dictionary. + * @param notifDict The dictionary to fill in. + * @return The dictionary with the keys filled in. This will be a separate instance from \a notifDict. + * @discussion This function examines the \a notifDict for missing keys, and + * tries to get them from the last known registration dictionary. As of 1.1, + * the keys that it will look for are: + * + * \li GROWL_APP_NAME + * \li GROWL_APP_ICON_DATA + * + * @since Growl.framework 1.1 + */ ++ (NSDictionary *) notificationDictionaryByFillingInDictionary:(NSDictionary *)regDict; + ++ (NSDictionary *) frameworkInfoDictionary; + +#pragma mark - + +/*! + *@method growlURLSchemeAvailable + *@abstract Lets the app know whether growl:// is registered on the system, used for certain methods below this + *@return Returns whether growl:// is registered on the system + *@discussion Methods such as openGrowlPreferences rely on the growl:// URL scheme to function + * Further, this method can provide a check on whether Growl is installed, + * however, the framework will not be relying on this method for choosing when/how to notify, + * and it is not recommended that the app rely on it for other than whether to use growl:// methods + *@since Growl.framework 1.4 + */ ++ (BOOL) isGrowlURLSchemeAvailable; + +/*! + * @method openGrowlPreferences: + * @abstract Open Growl preferences, optionally to this app's settings, growl:// method + * @param showApp Whether to show the application's settings, otherwise just opens to the last position + * @return Return's whether opening the URL was succesfull or not. + * @discussion Will launch if Growl is installed, but not running, and open the preferences window + * Uses growl:// URL scheme + * @since Growl.framework 1.4 + */ ++ (BOOL) openGrowlPreferences:(BOOL)showApp; + +@end + +//------------------------------------------------------------------------------ +#pragma mark - + +/*! + * @protocol GrowlApplicationBridgeDelegate + * @abstract Required protocol for the Growl delegate. + * @discussion The methods in this protocol are optional and are called + * automatically as needed by GrowlApplicationBridge. See + * +[GrowlApplicationBridge setGrowlDelegate:]. + * See also GrowlApplicationBridgeDelegate_InformalProtocol. + */ + +@protocol GrowlApplicationBridgeDelegate + +@optional + +/*! + * @method registrationDictionaryForGrowl + * @abstract Return the dictionary used to register this application with Growl. + * @discussion The returned dictionary gives Growl the complete list of + * notifications this application will ever send, and it also specifies which + * notifications should be enabled by default. Each is specified by an array + * of NSString objects. + * + * For most applications, these two arrays can be the same (if all sent + * notifications should be displayed by default). + * + * The NSString objects of these arrays will correspond to the + * notificationName: parameter passed in + * +[GrowlApplicationBridge + * notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:] calls. + * + * The dictionary should have the required key object pairs: + * key: GROWL_NOTIFICATIONS_ALL object: NSArray of NSString objects + * key: GROWL_NOTIFICATIONS_DEFAULT object: NSArray of NSString objects + * + * The dictionary may have the following key object pairs: + * key: GROWL_NOTIFICATIONS_HUMAN_READABLE_NAMES object: NSDictionary of key: notification name object: human-readable notification name + * + * You do not need to implement this method if you have an auto-discoverable + * plist file in your app bundle. (XXX refer to more information on that) + * + * @result The NSDictionary to use for registration. + */ +- (NSDictionary *) registrationDictionaryForGrowl; + +/*! + * @method applicationNameForGrowl + * @abstract Return the name of this application which will be used for Growl bookkeeping. + * @discussion This name is used both internally and in the Growl preferences. + * + * This should remain stable between different versions and incarnations of + * your application. + * For example, "SurfWriter" is a good app name, whereas "SurfWriter 2.0" and + * "SurfWriter Lite" are not. + * + * You do not need to implement this method if you are providing the + * application name elsewhere, meaning in an auto-discoverable plist file in + * your app bundle (XXX refer to more information on that) or in the result + * of -registrationDictionaryForGrowl. + * + * @result The name of the application using Growl. + */ +- (NSString *) applicationNameForGrowl; + +/*! + * @method applicationIconForGrowl + * @abstract Return the NSImage to treat as the application icon. + * @discussion The delegate may optionally return an NSImage + * object to use as the application icon. If this method is not implemented, + * {{{-applicationIconDataForGrowl}}} is tried. If that method is not + * implemented, the application's own icon is used. Neither method is + * generally needed. + * @result The NSImage to treat as the application icon. + */ +- (NSImage *) applicationIconForGrowl; + +/*! + * @method applicationIconDataForGrowl + * @abstract Return the NSData to treat as the application icon. + * @discussion The delegate may optionally return an NSData + * object to use as the application icon; if this is not implemented, the + * application's own icon is used. This is not generally needed. + * @result The NSData to treat as the application icon. + * @deprecated In version 1.1, in favor of {{{-applicationIconForGrowl}}}. + */ +- (NSData *) applicationIconDataForGrowl; + +/*! + * @method growlIsReady + * @abstract Informs the delegate that Growl has launched. + * @discussion Informs the delegate that Growl (specifically, the + * GrowlHelperApp) was launched successfully. The application can take actions + * with the knowledge that Growl is installed and functional. + */ +- (void) growlIsReady; + +/*! + * @method growlNotificationWasClicked: + * @abstract Informs the delegate that a Growl notification was clicked. + * @discussion Informs the delegate that a Growl notification was clicked. It + * is only sent for notifications sent with a non-nil + * clickContext, so if you want to receive a message when a notification is + * clicked, clickContext must not be nil when calling + * +[GrowlApplicationBridge notifyWithTitle: description:notificationName:iconData:priority:isSticky:clickContext:]. + * @param clickContext The clickContext passed when displaying the notification originally via +[GrowlApplicationBridge notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:]. + */ +- (void) growlNotificationWasClicked:(id)clickContext; + +/*! + * @method growlNotificationTimedOut: + * @abstract Informs the delegate that a Growl notification timed out. + * @discussion Informs the delegate that a Growl notification timed out. It + * is only sent for notifications sent with a non-nil + * clickContext, so if you want to receive a message when a notification is + * clicked, clickContext must not be nil when calling + * +[GrowlApplicationBridge notifyWithTitle: description:notificationName:iconData:priority:isSticky:clickContext:]. + * @param clickContext The clickContext passed when displaying the notification originally via +[GrowlApplicationBridge notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:]. + */ +- (void) growlNotificationTimedOut:(id)clickContext; + + +/*! + * @method hasNetworkClientEntitlement + * @abstract Used only in sandboxed situations since we don't know whether the app has com.apple.security.network.client entitlement + * @discussion GrowlDelegate calls to find out if we have the com.apple.security.network.client entitlement, + * since we can't find this out without hitting the sandbox. We only call it if we detect that the application is sandboxed. + */ +- (BOOL) hasNetworkClientEntitlement; + +@end + +#pragma mark - + +#endif /* __GrowlApplicationBridge_h__ */ diff --git a/Mac/Growl.framework/Versions/A/Headers/GrowlDefines.h b/Mac/Growl.framework/Versions/A/Headers/GrowlDefines.h new file mode 100644 index 0000000..0a196f1 --- /dev/null +++ b/Mac/Growl.framework/Versions/A/Headers/GrowlDefines.h @@ -0,0 +1,386 @@ +// +// GrowlDefines.h +// + +#ifndef _GROWLDEFINES_H +#define _GROWLDEFINES_H + +#ifdef __OBJC__ +#define XSTR(x) (@x) +#else +#define XSTR CFSTR +#endif + +/*! @header GrowlDefines.h + * @abstract Defines all the notification keys. + * @discussion Defines all the keys used for registration with Growl and for + * Growl notifications. + * + * Most applications should use the functions or methods of Growl.framework + * instead of posting notifications such as those described here. + * @updated 2004-01-25 + */ + +// UserInfo Keys for Registration +#pragma mark UserInfo Keys for Registration + +/*! @group Registration userInfo keys */ +/* @abstract Keys for the userInfo dictionary of a GROWL_APP_REGISTRATION distributed notification. + * @discussion The values of these keys describe the application and the + * notifications it may post. + * + * Your application must register with Growl before it can post Growl + * notifications (and have them not be ignored). However, as of Growl 0.6, + * posting GROWL_APP_REGISTRATION notifications directly is no longer the + * preferred way to register your application. Your application should instead + * use Growl.framework's delegate system. + * See +[GrowlApplicationBridge setGrowlDelegate:] or Growl_SetDelegate for + * more information. + */ + +/*! @defined GROWL_APP_NAME + * @abstract The name of your application. + * @discussion The name of your application. This should remain stable between + * different versions and incarnations of your application. + * For example, "SurfWriter" is a good app name, whereas "SurfWriter 2.0" and + * "SurfWriter Lite" are not. + */ +#define GROWL_APP_NAME XSTR("ApplicationName") +/*! @defined GROWL_APP_ID + * @abstract The bundle identifier of your application. + * @discussion The bundle identifier of your application. This key should + * be unique for your application while there may be several applications + * with the same GROWL_APP_NAME. + * This key is optional. + */ +#define GROWL_APP_ID XSTR("ApplicationId") +/*! @defined GROWL_APP_ICON_DATA + * @abstract The image data for your application's icon. + * @discussion Image data representing your application's icon. This may be + * superimposed on a notification icon as a badge, used as the notification + * icon when a notification-specific icon is not supplied, or ignored + * altogether, depending on the display. Must be in a format supported by + * NSImage, such as TIFF, PNG, GIF, JPEG, BMP, PICT, or PDF. + * + * Optional. Not supported by all display plugins. + */ +#define GROWL_APP_ICON_DATA XSTR("ApplicationIcon") +/*! @defined GROWL_NOTIFICATIONS_DEFAULT + * @abstract The array of notifications to turn on by default. + * @discussion These are the names of the notifications that should be enabled + * by default when your application registers for the first time. If your + * application reregisters, Growl will look here for any new notification + * names found in GROWL_NOTIFICATIONS_ALL, but ignore any others. + */ +#define GROWL_NOTIFICATIONS_DEFAULT XSTR("DefaultNotifications") +/*! @defined GROWL_NOTIFICATIONS_ALL + * @abstract The array of all notifications your application can send. + * @discussion These are the names of all of the notifications that your + * application may post. See GROWL_NOTIFICATION_NAME for a discussion of good + * notification names. + */ +#define GROWL_NOTIFICATIONS_ALL XSTR("AllNotifications") +/*! @defined GROWL_NOTIFICATIONS_HUMAN_READABLE_DESCRIPTIONS + * @abstract A dictionary of human-readable names for your notifications. + * @discussion By default, the Growl UI will display notifications by the names given in GROWL_NOTIFICATIONS_ALL + * which correspond to the GROWL_NOTIFICATION_NAME. This dictionary specifies the human-readable name to display. + * The keys of the dictionary are GROWL_NOTIFICATION_NAME strings; the objects are the human-readable versions. + * For any GROWL_NOTIFICATION_NAME not specific in this dictionary, the GROWL_NOTIFICATION_NAME will be displayed. + * + * This key is optional. + */ +#define GROWL_NOTIFICATIONS_HUMAN_READABLE_NAMES XSTR("HumanReadableNames") +/*! @defined GROWL_NOTIFICATIONS_DESCRIPTIONS +* @abstract A dictionary of descriptions of _when_ each notification occurs +* @discussion This is an NSDictionary whose keys are GROWL_NOTIFICATION_NAME strings and whose objects are +* descriptions of _when_ each notification occurs, such as "You received a new mail message" or +* "A file finished downloading". +* +* This key is optional. +*/ +#define GROWL_NOTIFICATIONS_DESCRIPTIONS XSTR("NotificationDescriptions") +/*! @defined GROWL_NOTIFICATIONS_ICONS + * @abstract A dictionary of icons for each notification + * @discussion This is an NSDictionary whose keys are GROWL_NOTIFICATION_NAME strings and whose objects are + * icons for each notification, for GNTP spec + * + * This key is optional. + */ +#define GROWL_NOTIFICATIONS_ICONS XSTR("NotificationIcons") + +/*! @defined GROWL_TICKET_VERSION + * @abstract The version of your registration ticket. + * @discussion Include this key in a ticket plist file that you put in your + * application bundle for auto-discovery. The current ticket version is 1. + */ +#define GROWL_TICKET_VERSION XSTR("TicketVersion") +// UserInfo Keys for Notifications +#pragma mark UserInfo Keys for Notifications + +/*! @group Notification userInfo keys */ +/* @abstract Keys for the userInfo dictionary of a GROWL_NOTIFICATION distributed notification. + * @discussion The values of these keys describe the content of a Growl + * notification. + * + * Not all of these keys are supported by all displays. Only the name, title, + * and description of a notification are universal. Most of the built-in + * displays do support all of these keys, and most other visual displays + * probably will also. But, as of 0.6, the Log, MailMe, and Speech displays + * support only textual data. + */ + +/*! @defined GROWL_NOTIFICATION_NAME + * @abstract The name of the notification. + * @discussion The name of the notification. Note that if you do not define + * GROWL_NOTIFICATIONS_HUMAN_READABLE_NAMES when registering your ticket originally this name + * will the one displayed within the Growl preference pane and should be human-readable. + */ +#define GROWL_NOTIFICATION_NAME XSTR("NotificationName") +/*! @defined GROWL_NOTIFICATION_TITLE + * @abstract The title to display in the notification. + * @discussion The title of the notification. Should be very brief. + * The title usually says what happened, e.g. "Download complete". + */ +#define GROWL_NOTIFICATION_TITLE XSTR("NotificationTitle") +/*! @defined GROWL_NOTIFICATION_DESCRIPTION + * @abstract The description to display in the notification. + * @discussion The description should be longer and more verbose than the title. + * The description usually tells the subject of the action, + * e.g. "Growl-0.6.dmg downloaded in 5.02 minutes". + */ +#define GROWL_NOTIFICATION_DESCRIPTION XSTR("NotificationDescription") +/*! @defined GROWL_NOTIFICATION_ICON + * @discussion Image data for the notification icon. Image data must be in a format + * supported by NSImage, such as TIFF, PNG, GIF, JPEG, BMP, PICT, or PDF. + * + * Optional. Not supported by all display plugins. + */ +#define GROWL_NOTIFICATION_ICON_DATA XSTR("NotificationIcon") +/*! @defined GROWL_NOTIFICATION_APP_ICON + * @discussion Image data for the application icon, in case GROWL_APP_ICON does + * not apply for some reason. Image data be in a format supported by NSImage, such + * as TIFF, PNG, GIF, JPEG, BMP, PICT, or PDF. + * + * Optional. Not supported by all display plugins. + */ +#define GROWL_NOTIFICATION_APP_ICON_DATA XSTR("NotificationAppIcon") +/*! @defined GROWL_NOTIFICATION_PRIORITY + * @discussion The priority of the notification as an integer number from + * -2 to +2 (+2 being highest). + * + * Optional. Not supported by all display plugins. + */ +#define GROWL_NOTIFICATION_PRIORITY XSTR("NotificationPriority") +/*! @defined GROWL_NOTIFICATION_STICKY + * @discussion A Boolean number controlling whether the notification is sticky. + * + * Optional. Not supported by all display plugins. + */ +#define GROWL_NOTIFICATION_STICKY XSTR("NotificationSticky") +/*! @defined GROWL_NOTIFICATION_CLICK_CONTEXT + * @abstract Identifies which notification was clicked. + * @discussion An identifier for the notification for clicking purposes. + * + * This will be passed back to the application when the notification is + * clicked. It must be plist-encodable (a data, dictionary, array, number, or + * string object), and it should be unique for each notification you post. + * A good click context would be a UUID string returned by NSProcessInfo or + * CFUUID. + * + * Optional. Not supported by all display plugins. + */ +#define GROWL_NOTIFICATION_CLICK_CONTEXT XSTR("NotificationClickContext") + +/*! @defined GROWL_NOTIFICATION_IDENTIFIER + * @abstract An identifier for the notification for coalescing purposes. + * Notifications with the same identifier fall into the same class; only + * the last notification of a class is displayed on the screen. If a + * notification of the same class is currently being displayed, it is + * replaced by this notification. + * + * Optional. Not supported by all display plugins. + */ +#define GROWL_NOTIFICATION_IDENTIFIER XSTR("GrowlNotificationIdentifier") + +/*! @defined GROWL_APP_PID + * @abstract The process identifier of the process which sends this + * notification. If this field is set, the application will only receive + * clicked and timed out notifications which originate from this process. + * + * Optional. + */ +#define GROWL_APP_PID XSTR("ApplicationPID") + +/*! @defined GROWL_NOTIFICATION_PROGRESS +* @abstract If this key is set, it should contain a double value wrapped +* in a NSNumber which describes some sort of progress (from 0.0 to 100.0). +* If this is key is not set, no progress bar is shown. +* +* Optional. Not supported by all display plugins. +*/ +#define GROWL_NOTIFICATION_PROGRESS XSTR("NotificationProgress") + +/*! @defined GROWL_NOTIFICATION_ALREADY_SHOWN + * @abstract If this key is set, it should contain a bool value wrapped + * in a NSNumber which describes whether the notification has + * already been displayed, for instance by built in Notification + * Center support. This value can be used to allow display + * plugins to skip a notification, while still allowing Growl + * actions to run on them. + * + * Optional. Not supported by all display plugins. + */ +#define GROWL_NOTIFICATION_ALREADY_SHOWN XSTR("AlreadyShown") + + +// Notifications +#pragma mark Notifications + +/*! @group Notification names */ +/* @abstract Names of distributed notifications used by Growl. + * @discussion These are notifications used by applications (directly or + * indirectly) to interact with Growl, and by Growl for interaction between + * its components. + * + * Most of these should no longer be used in Growl 0.6 and later, in favor of + * Growl.framework's GrowlApplicationBridge APIs. + */ + +/*! @defined GROWL_APP_REGISTRATION + * @abstract The distributed notification for registering your application. + * @discussion This is the name of the distributed notification that can be + * used to register applications with Growl. + * + * The userInfo dictionary for this notification can contain these keys: + *
    + *
  • GROWL_APP_NAME
  • + *
  • GROWL_APP_ICON_DATA
  • + *
  • GROWL_NOTIFICATIONS_ALL
  • + *
  • GROWL_NOTIFICATIONS_DEFAULT
  • + *
+ * + * No longer recommended as of Growl 0.6. An alternate method of registering + * is to use Growl.framework's delegate system. + * See +[GrowlApplicationBridge setGrowlDelegate:] or Growl_SetDelegate for + * more information. + */ +#define GROWL_APP_REGISTRATION XSTR("GrowlApplicationRegistrationNotification") +/*! @defined GROWL_APP_REGISTRATION_CONF + * @abstract The distributed notification for confirming registration. + * @discussion The name of the distributed notification sent to confirm the + * registration. Used by the Growl preference pane. Your application probably + * does not need to use this notification. + */ +#define GROWL_APP_REGISTRATION_CONF XSTR("GrowlApplicationRegistrationConfirmationNotification") +/*! @defined GROWL_NOTIFICATION + * @abstract The distributed notification for Growl notifications. + * @discussion This is what it all comes down to. This is the name of the + * distributed notification that your application posts to actually send a + * Growl notification. + * + * The userInfo dictionary for this notification can contain these keys: + *
    + *
  • GROWL_NOTIFICATION_NAME (required)
  • + *
  • GROWL_NOTIFICATION_TITLE (required)
  • + *
  • GROWL_NOTIFICATION_DESCRIPTION (required)
  • + *
  • GROWL_NOTIFICATION_ICON
  • + *
  • GROWL_NOTIFICATION_APP_ICON
  • + *
  • GROWL_NOTIFICATION_PRIORITY
  • + *
  • GROWL_NOTIFICATION_STICKY
  • + *
  • GROWL_NOTIFICATION_CLICK_CONTEXT
  • + *
  • GROWL_APP_NAME (required)
  • + *
+ * + * No longer recommended as of Growl 0.6. Three alternate methods of posting + * notifications are +[GrowlApplicationBridge notifyWithTitle:description:notificationName:iconData:priority:isSticky:clickContext:], + * Growl_NotifyWithTitleDescriptionNameIconPriorityStickyClickContext, and + * Growl_PostNotification. + */ +#define GROWL_NOTIFICATION XSTR("GrowlNotification") +/*! @defined GROWL_PING + * @abstract A distributed notification to check whether Growl is running. + * @discussion This is used by the Growl preference pane. If it receives a + * GROWL_PONG, the preference pane takes this to mean that Growl is running. + */ +#define GROWL_PING XSTR("Honey, Mind Taking Out The Trash") +/*! @defined GROWL_PONG + * @abstract The distributed notification sent in reply to GROWL_PING. + * @discussion GrowlHelperApp posts this in reply to GROWL_PING. + */ +#define GROWL_PONG XSTR("What Do You Want From Me, Woman") +/*! @defined GROWL_IS_READY + * @abstract The distributed notification sent when Growl starts up. + * @discussion GrowlHelperApp posts this when it has begin listening on all of + * its sources for new notifications. GrowlApplicationBridge (in + * Growl.framework), upon receiving this notification, reregisters using the + * registration dictionary supplied by its delegate. + */ +#define GROWL_IS_READY XSTR("Lend Me Some Sugar; I Am Your Neighbor!") + + +/*! @defined GROWL_DISTRIBUTED_NOTIFICATION_CLICKED_SUFFIX + * @abstract Part of the name of the distributed notification sent when a supported notification is clicked. + * @discussion When a Growl notification with a click context is clicked on by + * the user, Growl posts a distributed notification whose name is in the format: + * [NSString stringWithFormat:@"%@-%d-%@", appName, pid, GROWL_DISTRIBUTED_NOTIFICATION_CLICKED_SUFFIX] + * The GrowlApplicationBridge responds to this notification by calling a callback in its delegate. + */ +#define GROWL_DISTRIBUTED_NOTIFICATION_CLICKED_SUFFIX XSTR("GrowlClicked!") + +/*! @defined GROWL_DISTRIBUTED_NOTIFICATION_TIMED_OUT_SUFFIX + * @abstract Part of the name of the distributed notification sent when a supported notification times out without being clicked. + * @discussion When a Growl notification with a click context times out, Growl posts a distributed notification + * whose name is in the format: + * [NSString stringWithFormat:@"%@-%d-%@", appName, pid, GROWL_DISTRIBUTED_NOTIFICATION_TIMED_OUT_SUFFIX] + * The GrowlApplicationBridge responds to this notification by calling a callback in its delegate. + * NOTE: The user may have actually clicked the 'close' button; this triggers an *immediate* time-out of the notification. + */ +#define GROWL_DISTRIBUTED_NOTIFICATION_TIMED_OUT_SUFFIX XSTR("GrowlTimedOut!") + +/*! @defined GROWL_DISTRIBUTED_NOTIFICATION_NOTIFICATIONCENTER_ON + * @abstract The distributed notification sent when the Notification Center support is toggled on in Growl 2.0 + * @discussion When the user enables Notification Center support in Growl 2.0, this notification is sent + * to inform all running apps that they should now speak to Notification Center directly. + */ +#define GROWL_DISTRIBUTED_NOTIFICATION_NOTIFICATIONCENTER_ON XSTR("GrowlNotificationCenterOn!") + +/*! @defined GROWL_DISTRIBUTED_NOTIFICATION_NOTIFICATIONCENTER_OFF + * @abstract The distributed notification sent when the Notification Center support is toggled off in Growl 2.0 + * @discussion When the user enables Notification Center support in Growl 2.0, this notification is sent + * to inform all running apps that they should no longer speak to Notification Center directly. + */ +#define GROWL_DISTRIBUTED_NOTIFICATION_NOTIFICATIONCENTER_OFF XSTR("GrowlNotificationCenterOff!") + +/*! @defined GROWL_DISTRIBUTED_NOTIFICATION_NOTIFICATIONCENTER_QUERY + * @abstract The distributed notification sent by an application to query Growl 2.0's notification center support. + * @discussion When an app starts up, it will send this query to get Growl 2.0 to spit out whether notification + * center support is on or off. + */ +#define GROWL_DISTRIBUTED_NOTIFICATION_NOTIFICATIONCENTER_QUERY XSTR("GrowlNotificationCenterYN?") + + +/*! @group Other symbols */ +/* Symbols which don't fit into any of the other categories. */ + +/*! @defined GROWL_KEY_CLICKED_CONTEXT + * @abstract Used internally as the key for the clickedContext passed over DNC. + * @discussion This key is used in GROWL_NOTIFICATION_CLICKED, and contains the + * click context that was supplied in the original notification. + */ +#define GROWL_KEY_CLICKED_CONTEXT XSTR("ClickedContext") +/*! @defined GROWL_REG_DICT_EXTENSION + * @abstract The filename extension for registration dictionaries. + * @discussion The GrowlApplicationBridge in Growl.framework registers with + * Growl by creating a file with the extension of .(GROWL_REG_DICT_EXTENSION) + * and opening it in the GrowlHelperApp. This happens whether or not Growl is + * running; if it was stopped, it quits immediately without listening for + * notifications. + */ +#define GROWL_REG_DICT_EXTENSION XSTR("growlRegDict") + + +#define GROWL_POSITION_PREFERENCE_KEY @"GrowlSelectedPosition" + +#define GROWL_PLUGIN_CONFIG_ID XSTR("GrowlPluginConfigurationID") + +#endif //ndef _GROWLDEFINES_H diff --git a/Mac/Growl.framework/Versions/A/Headers/GrowlPluginPreferenceStrings.h b/Mac/Growl.framework/Versions/A/Headers/GrowlPluginPreferenceStrings.h new file mode 100644 index 0000000..4632ba6 --- /dev/null +++ b/Mac/Growl.framework/Versions/A/Headers/GrowlPluginPreferenceStrings.h @@ -0,0 +1,67 @@ +// +// GrowlPluginPreferenceStrings.h +// Growl +// +// Created by Daniel Siemer on 1/30/12. +// Copyright (c) 2012 The Growl Project. All rights reserved. +// + +/* FOR GROWL DEVELOPED COCOA PLUGINS ONLY AT THIS TIME, NOT STABLE */ + +#import + +#define GrowlDisplayOpacity NSLocalizedStringFromTable(@"Opacity:", @"PluginPrefStrings", @"How clear the display is") +#define GrowlDisplayDuration NSLocalizedStringFromTable(@"Duration:", @"PluginPrefStrings", @"How long a notification will stay on screen") + +#define GrowlDisplayPriority NSLocalizedStringFromTable(@"Priority: (low to high)", @"PluginPrefStrings", @"Label for columns of color wells for various priority levels") +#define GrowlDisplayPriorityLow NSLocalizedStringFromTable(@"Very Low", @"PluginPrefStrings", @"Notification Priority Very Low") +#define GrowlDisplayPriorityModerate NSLocalizedStringFromTable(@"Moderate", @"PluginPrefStrings", @"Notification Priority Moderate") +#define GrowlDisplayPriorityNormal NSLocalizedStringFromTable(@"Normal", @"PluginPrefStrings", @"Notification Priority Normal") +#define GrowlDisplayPriorityHigh NSLocalizedStringFromTable(@"High", @"PluginPrefStrings", @"Notification Priority High") +#define GrowlDisplayPriorityEmergency NSLocalizedStringFromTable(@"Emergency", @"PluginPrefStrings", @"Notification Priority Emergency") + +#define GrowlDisplayTextColor NSLocalizedStringFromTable(@"Text", @"PluginPrefStrings", @"Label for row of color wells for the text element of the plugin") +#define GrowlDisplayBackgroundColor NSLocalizedStringFromTable(@"Background", @"PluginPrefStrings", @"Label for row of color wells for the background of the plugin") + +#define GrowlDisplayLimitLines NSLocalizedStringFromTable(@"Limit to 2-5 lines", @"PluginPrefStrings", @"Checkbox to limit the display to 2-5 lines") +#define GrowlDisplayScreen NSLocalizedStringFromTable(@"Screen:", @"PluginPrefStrings", @"Label for box to select screen for display to use") +#define GrowlDisplaySize NSLocalizedStringFromTable(@"Size:", @"PluginPrefStrings", @"Label for pop up box for selecting the size of the display") +#define GrowlDisplaySizeNormal NSLocalizedStringFromTable(@"Normal", @"PluginPrefStrings", @"Normal size for the display") +#define GrowlDisplaySizeLarge NSLocalizedStringFromTable(@"Large", @"PluginPrefStrings", @"Large size for the display") +#define GrowlDisplaySizeSmall NSLocalizedStringFromTable(@"Small", @"PluginPrefStrings", @"Small size for the display") + +#define GrowlDisplayFloatingIcon NSLocalizedStringFromTable(@"Floating Icon", @"PluginPrefStrings", @"Label for checkbox that says to do a floating icon") + +#define GrowlDisplayEffect NSLocalizedStringFromTable(@"Effect:", @"PluginPrefStrings", @"Label for the effect to use") +#define GrowlDisplayEffectSlide NSLocalizedStringFromTable(@"Slide", @"PluginPrefStrings", @"A slide effect") +#define GrowlDisplayEffectFade NSLocalizedStringFromTable(@"Fade", @"PluginPrefStrings", @"A fade effect") + +@interface GrowlPluginPreferenceStrings : NSObject + +@property (nonatomic, retain) NSString *growlDisplayOpacity; +@property (nonatomic, retain) NSString *growlDisplayDuration; + +@property (nonatomic, retain) NSString *growlDisplayPriority; +@property (nonatomic, retain) NSString *growlDisplayPriorityVeryLow; +@property (nonatomic, retain) NSString *growlDisplayPriorityModerate; +@property (nonatomic, retain) NSString *growlDisplayPriorityNormal; +@property (nonatomic, retain) NSString *growlDisplayPriorityHigh; +@property (nonatomic, retain) NSString *growlDisplayPriorityEmergency; + +@property (nonatomic, retain) NSString *growlDisplayTextColor; +@property (nonatomic, retain) NSString *growlDisplayBackgroundColor; + +@property (nonatomic, retain) NSString *growlDisplayLimitLines; +@property (nonatomic, retain) NSString *growlDisplayScreen; +@property (nonatomic, retain) NSString *growlDisplaySize; +@property (nonatomic, retain) NSString *growlDisplaySizeNormal; +@property (nonatomic, retain) NSString *growlDisplaySizeLarge; +@property (nonatomic, retain) NSString *growlDisplaySizeSmall; + +@property (nonatomic, retain) NSString *growlDisplayFloatingIcon; + +@property (nonatomic, retain) NSString *effectLabel; +@property (nonatomic, retain) NSString *slideEffect; +@property (nonatomic, retain) NSString *fadeEffect; + +@end diff --git a/Mac/Growl.framework/Versions/A/Resources/Info.plist b/Mac/Growl.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..4d9bd5f --- /dev/null +++ b/Mac/Growl.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,40 @@ + + + + + BuildMachineOSBuild + 12A269 + CFBundleDevelopmentRegion + English + CFBundleExecutable + Growl + CFBundleIdentifier + com.growl.growlframework + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.0 + CFBundleSignature + GRRR + CFBundleVersion + 2.0 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 4F250 + DTPlatformVersion + GM + DTSDKBuild + 12A264 + DTSDKName + macosx10.8 + DTXcode + 0440 + DTXcodeBuild + 4F250 + NSPrincipalClass + GrowlApplicationBridge + + diff --git a/Mac/Growl.framework/Versions/A/_CodeSignature/CodeResources b/Mac/Growl.framework/Versions/A/_CodeSignature/CodeResources new file mode 100644 index 0000000..d4a95e2 --- /dev/null +++ b/Mac/Growl.framework/Versions/A/_CodeSignature/CodeResources @@ -0,0 +1,34 @@ + + + + + files + + Resources/Info.plist + + lnx8exuPwE/bsUq32R5DXDQholc= + + + rules + + ^Resources/ + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^version.plist$ + + + + diff --git a/Mac/Growl.framework/Versions/Current b/Mac/Growl.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Mac/Growl.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Mac/MimeType.h b/Mac/MimeType.h new file mode 100644 index 0000000..2072838 --- /dev/null +++ b/Mac/MimeType.h @@ -0,0 +1,13 @@ +// +// MimeType.h +// bungloo +// +// Created by Jeena on 23/11/2012. +// +// + +#import + +@interface MimeType : NSObject ++(NSString *)mimeTypeForFileAtPath:(NSString *)path error:(NSError **)err; +@end diff --git a/Mac/MimeType.m b/Mac/MimeType.m new file mode 100644 index 0000000..f1327c4 --- /dev/null +++ b/Mac/MimeType.m @@ -0,0 +1,27 @@ +// +// MimeType.m +// bungloo +// +// Created by Jeena on 23/11/2012. +// +// + +#import "MimeType.h" + +@implementation MimeType + ++(NSString *)mimeTypeForFileAtPath:(NSString *)path error:(NSError **)err { + NSString *uti, *mimeType = nil; + + if (!(uti = [[NSWorkspace sharedWorkspace] typeOfFile:path error:err])) + return nil; + if (err) + *err = nil; + + if ((mimeType = (NSString *)UTTypeCopyPreferredTagWithClass((CFStringRef)uti, kUTTagClassMIMEType))) + mimeType = NSMakeCollectable(mimeType); + + return mimeType; +} + +@end diff --git a/Mac/NSData+Base64.h b/Mac/NSData+Base64.h new file mode 100644 index 0000000..fc674c8 --- /dev/null +++ b/Mac/NSData+Base64.h @@ -0,0 +1,46 @@ +// +// Created by Cédric Luthi on 2012-02-24. +// Copyright (c) 2012 Cédric Luthi. All rights reserved. +// + +#import "NSData+Base64.h" + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +@implementation NSData (Base64) + ++ (id) dataWithBase64Encoding_xcd:(NSString *)base64Encoding +{ + if ([base64Encoding length] % 4 != 0) + return nil; + + NSString *plist = [NSString stringWithFormat:@"%@", base64Encoding]; + return [NSPropertyListSerialization propertyListWithData:[plist dataUsingEncoding:NSASCIIStringEncoding] options:0 format:NULL error:NULL]; +} + +- (NSString *) base64Encoding_xcd +{ + NSData *plist = [NSPropertyListSerialization dataWithPropertyList:self format:NSPropertyListXMLFormat_v1_0 options:0 error:NULL]; + NSRange fullRange = NSMakeRange(0, [plist length]); + NSRange startRange = [plist rangeOfData:[@"" dataUsingEncoding:NSASCIIStringEncoding] options:0 range:fullRange]; + NSRange endRange = [plist rangeOfData:[@"" dataUsingEncoding:NSASCIIStringEncoding] options:NSDataSearchBackwards range:fullRange]; + if (startRange.location == NSNotFound || endRange.location == NSNotFound) + return nil; + + NSUInteger base64Location = startRange.location + startRange.length; + NSUInteger base64length = endRange.location - base64Location; + NSData *base64Data = [NSData dataWithBytesNoCopy:(void *)((uintptr_t)base64Location + (uintptr_t)[plist bytes]) length:base64length freeWhenDone:NO]; + NSString *base64Encoding = [[NSString alloc] initWithData:base64Data encoding:NSASCIIStringEncoding]; + base64Encoding = [base64Encoding stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]; + base64Encoding = [base64Encoding stringByReplacingOccurrencesOfString:@"\n" withString:@""]; + +#if __has_feature(objc_arc) + return base64Encoding; +#else + return [base64Encoding autorelease]; +#endif +} + +@end \ No newline at end of file diff --git a/Mac/NSData+Base64.m b/Mac/NSData+Base64.m new file mode 100644 index 0000000..1a71914 --- /dev/null +++ b/Mac/NSData+Base64.m @@ -0,0 +1,13 @@ +// +// Created by Cédric Luthi on 2012-02-24. +// Copyright (c) 2012 Cédric Luthi. All rights reserved. +// + +#import + +@interface NSData (Base64) + ++ (id) dataWithBase64Encoding_xcd:(NSString *)base64String; +- (NSString *) base64Encoding_xcd; + +@end \ No newline at end of file diff --git a/Mac/NewMessageWindow.h b/Mac/NewMessageWindow.h new file mode 100644 index 0000000..b8893ab --- /dev/null +++ b/Mac/NewMessageWindow.h @@ -0,0 +1,47 @@ +// +// NewMessageWindow.h +// bungloo +// +// Created by Jeena on 16.04.10. +// Licence: BSD (see attached LICENCE.txt file). +// + + +#import +#import + + +@interface NewMessageWindow : NSDocument +{ + IBOutlet NSTextField *textField; + IBOutlet NSTextField *counter; + NSMenu *addMenu; + NSButton *addMenuButton; + NSString *inReplyTostatusId; + NSString *inReplyToEntity; + NSMenuItem *addImage; + CLLocationManager *locationManager; + CLLocation *currentLocation; + NSString *imageFilePath; + NSButton *togglePrivateButton; +} + +@property (nonatomic, retain) IBOutlet NSTextField *textField; +@property (nonatomic, retain) IBOutlet NSTextField *counter; +@property (assign) IBOutlet NSMenu *addMenu; +@property (assign) IBOutlet NSButton *addMenuButton; +@property (retain, nonatomic) CLLocationManager *locationManager; +@property (retain, nonatomic) CLLocation *currentLocation; +@property (retain, nonatomic) NSString *imageFilePath; +@property (assign) IBOutlet NSButton *togglePrivateButton; + +- (IBAction)sendPost:(NSControl *)control; +- (void)inReplyTo:(NSString *)userName statusId:(NSString *)statusId withString:(NSString *)string; +- (void)withString:(NSString *)aString; +- (IBAction)addCurrentLocation:(id)sender; +- (IBAction)addImage:(id)sender; +- (IBAction)openAddMenu:(id)sender; +- (IBAction)togglePrivate:(id)sender; +- (void)setIsPrivate:(BOOL)isPrivate; + +@end diff --git a/Mac/NewMessageWindow.m b/Mac/NewMessageWindow.m new file mode 100644 index 0000000..c69e78c --- /dev/null +++ b/Mac/NewMessageWindow.m @@ -0,0 +1,344 @@ +// +// NewPostWindow.m +// bungloo +// +// Created by Jeena on 16.04.10. +// Licence: BSD (see attached LICENCE.txt file). +// + +#import "NewMessageWindow.h" +#import "Constants.h" +#import "PostModel.h" +#import "Controller.h" + +@interface NewMessageWindow (private) +- (BOOL)isCommandEnterEvent:(NSEvent *)e; +- (void)initLocationManager; +@end + +@implementation NewMessageWindow + +@synthesize addMenu; +@synthesize addMenuButton; +@synthesize textField, counter; +@synthesize locationManager, currentLocation; +@synthesize imageFilePath; +@synthesize togglePrivateButton; + +- (void)dealloc +{ + [locationManager stopUpdatingLocation]; + [locationManager release]; + [currentLocation release]; + [imageFilePath release]; + [super dealloc]; +} + +- (id)init +{ + self = [super init]; + if (self) + { + // Add your subclass-specific initialization here. + // If an error occurs here, send a [self release] message and return nil. + inReplyTostatusId = @""; + inReplyToEntity = @""; + } + return self; +} + +- (NSString *)windowNibName +{ + // Override returning the nib file name of the document + // If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead. + return @"NewMessageWindow"; +} + +- (NSString *)displayName +{ + return @"New Post"; +} + +- (void)windowControllerDidLoadNib:(NSWindowController *) aController +{ + [super windowControllerDidLoadNib:aController]; + // Add any code here that needs to be executed once the windowController has loaded the document's window. + [textField becomeFirstResponder]; + + // Enable Continous Spelling + NSTextView *textView = (NSTextView *)[[[self.windowControllers objectAtIndex:0] window] firstResponder];; + [textView setContinuousSpellCheckingEnabled:YES]; +} + +- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError +{ + // Insert code here to write your document to data of the specified type. If the given outError != NULL, ensure that you set *outError when returning nil. + + // You can also choose to override -fileWrapperOfType:error:, -writeToURL:ofType:error:, or -writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead. + + // For applications targeted for Panther or earlier systems, you should use the deprecated API -dataRepresentationOfType:. In this case you can also choose to override -fileWrapperRepresentationOfType: or -writeToFile:ofType: instead. + + if ( outError != NULL ) { + *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:NULL]; + } + return nil; +} + +- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError +{ + // Insert code here to read your document from the given data of the specified type. If the given outError != NULL, ensure that you set *outError when returning NO. + + // You can also choose to override -readFromFileWrapper:ofType:error: or -readFromURL:ofType:error: instead. + + // For applications targeted for Panther or earlier systems, you should use the deprecated API -loadDataRepresentation:ofType. In this case you can also choose to override -readFromFile:ofType: or -loadFileWrapperRepresentation:ofType: instead. + + if ( outError != NULL ) + { + *outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:NULL]; + } + return YES; +} + +- (void)inReplyTo:(NSString *)entity statusId:(NSString *)statusId withString:(NSString *)string +{ + [textField setStringValue:string]; + + NSInteger location = [string rangeOfString:@" "].location; + NSInteger length = 0; + if (location != NSNotFound) { + length = [[textField stringValue] length] - location - 1; + } + + + NSRange range = {location + 1, length}; + [[textField currentEditor] setSelectedRange:range]; + + [inReplyTostatusId release]; + inReplyTostatusId = statusId; + [inReplyTostatusId retain]; + + [inReplyToEntity release]; + inReplyToEntity = entity; + [inReplyToEntity retain]; + + [self controlTextDidChange:nil]; +} + +- (void)withString:(NSString *)aString +{ + [textField setStringValue:aString]; + NSRange range = {[[textField stringValue] length] , 0}; + [[textField currentEditor] setSelectedRange:range]; + NSLog(@"BB"); + + [self controlTextDidChange:nil]; +} + +- (IBAction)addCurrentLocation:(id)sender +{ + NSMenuItem *menuItem = (NSMenuItem *)sender; + if (!self.locationManager) + { + [menuItem setTitle:@"Current location not available"]; + [self initLocationManager]; + } + else + { + [self.locationManager stopUpdatingLocation]; + self.currentLocation = nil; + self.locationManager = nil; + [menuItem setTitle:@"Add current location"]; + } +} + +- (IBAction)openAddMenu:(id)sender +{ + NSRect frame = [(NSButton *)sender frame]; + NSPoint menuOrigin = [[(NSButton *)sender superview] convertPoint:NSMakePoint(frame.origin.x, frame.origin.y+frame.size.height) toView:nil]; + + NSEvent *event = [NSEvent mouseEventWithType:NSLeftMouseDown + location:menuOrigin + modifierFlags:NSLeftMouseDownMask // 0x100 + timestamp:NSTimeIntervalSince1970 + windowNumber:[[(NSButton *)sender window] windowNumber] + context:[[(NSButton *)sender window] graphicsContext] + eventNumber:0 + clickCount:1 + pressure:1]; + + [NSMenu popUpContextMenu:self.addMenu withEvent:event forView:self.addMenuButton]; +} + +- (IBAction)togglePrivate:(id)sender +{ + NSImage *image = [NSImage imageNamed:NSImageNameLockLockedTemplate]; + if (self.togglePrivateButton.image == [NSImage imageNamed:NSImageNameLockLockedTemplate]) + { + image = [NSImage imageNamed:NSImageNameLockUnlockedTemplate]; + } + [self.togglePrivateButton setImage:image]; +} + +- (void)setIsPrivate:(BOOL)isPrivate { + NSImage *image = [NSImage imageNamed:(isPrivate ? NSImageNameLockLockedTemplate : NSImageNameLockUnlockedTemplate)]; + [self.togglePrivateButton setImage:image]; +} + +-(void)controlTextDidChange:(NSNotification *)aNotification { + NSInteger c = MESSAGE_MAX_LENGTH - [[textField stringValue] length]; + [counter setIntValue:c]; + if(c < 0) { + [counter setTextColor:[NSColor redColor]]; + } else { + [counter setTextColor:[NSColor controlTextColor]]; + } +} + +- (void)initLocationManager +{ + self.locationManager = [[CLLocationManager alloc] init]; + [self.locationManager setDelegate:self]; + [self.locationManager setDesiredAccuracy:kCLLocationAccuracyBest]; + [self.locationManager setDistanceFilter:kCLDistanceFilterNone]; + [self.locationManager startUpdatingLocation]; +} + +- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation +{ + self.currentLocation = newLocation; + NSMenuItem *menuItem = [self.addMenu itemAtIndex:0]; + [menuItem setTitle:@"Remove current location"]; +} + +- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{ + NSLog(@"CLLocationManager Error: %@", error); + + NSMenuItem *menuItem = [self.addMenu itemAtIndex:0]; + [menuItem setTitle:@"Current location not available"]; +} + +- (IBAction)sendPostButtonPressed:(id)sender +{ + [self sendPost:self.textField]; +} + +#pragma mark Keyboard delegate methods + +- (IBAction)sendPost:(NSControl *)control { + BOOL emptyIsOk = self.currentLocation || self.imageFilePath; + if (emptyIsOk || ([[control stringValue] length] <= MESSAGE_MAX_LENGTH && [[control stringValue] length] > 0)) { + PostModel *post = [[[PostModel alloc] init] autorelease]; + post.text = [control stringValue]; + post.inReplyTostatusId = inReplyTostatusId; + post.inReplyToEntity = inReplyToEntity; + post.location = self.currentLocation; + post.imageFilePath = self.imageFilePath; + post.isPrivate = self.togglePrivateButton.image == [NSImage imageNamed:NSImageNameLockLockedTemplate]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"sendPost" object:post]; + [self close]; + } else { + NSBeep(); + } + +} + +- (BOOL)isCommandEnterEvent:(NSEvent *)e { + NSUInteger flags = (e.modifierFlags & NSDeviceIndependentModifierFlagsMask); + BOOL isCommand = (flags & NSCommandKeyMask) == NSCommandKeyMask; + BOOL isEnter = (e.keyCode == 0x24); // VK_RETURN + return (isCommand && isEnter); +} + +- (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor doCommandBySelector:(SEL)commandSelector +{ + BOOL retval = NO; + + BOOL isEnter = [[NSApp currentEvent] keyCode] == 76; + + if (commandSelector == @selector(insertNewline:) && !isEnter) { + + NSText *text = [[textField window] fieldEditor:YES forObject:nil]; + + NSRange range = [text selectedRange]; + NSString *stringBefore = [textField.stringValue substringToIndex:range.location]; + NSString *stringAfter = [textField.stringValue substringFromIndex:range.location + range.length]; + + textField.stringValue = [NSString stringWithFormat:@"%@\n%@", stringBefore, stringAfter]; + + NSRange r = NSMakeRange(range.location + 1, 0); + [text scrollRangeToVisible:r]; + [text setSelectedRange:r]; + + retval = YES; // causes Apple to NOT fire the default enter action + } + else if (commandSelector == @selector(noop:) && isEnter) { + retval = YES; + [self sendPost:control]; + } + + return retval; +} + +#pragma mark Add images + +- (IBAction)addImage:(id)sender +{ + NSMenuItem *menuItem = (NSMenuItem *)sender; + + if (!self.imageFilePath) + { + [menuItem setTitle:@"Remove photo"]; + + NSOpenPanel* openDlg = [NSOpenPanel openPanel]; + [openDlg setPrompt:@"Select"]; + [openDlg setDelegate:self]; + + // Enable the selection of files in the dialog. + [openDlg setCanChooseFiles:YES]; + + // Enable the selection of directories in the dialog. + [openDlg setCanChooseDirectories:NO]; + + // Display the dialog. If the OK button was pressed, + // process the files. + if ( [openDlg runModalForDirectory:nil file:nil] == NSOKButton ) + { + // Get an array containing the full filenames of all + // files and directories selected. + NSArray* files = [openDlg filenames]; + + // Loop through all the files and process them. + for( int i = 0; i < [files count]; i++ ) + { + self.imageFilePath = [files objectAtIndex:i]; + } + } + } + else + { + self.imageFilePath = nil; + [menuItem setTitle:@"Add photo"]; + } +} + +-(BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename +{ + NSString* ext = [filename pathExtension]; + if ([ext isEqualToString:@""] || [ext isEqualToString:@"/"] || ext == nil || ext == NULL || [ext length] < 1) { + return YES; + } + + NSEnumerator* tagEnumerator = [[NSArray arrayWithObjects:@"png", @"jpg", @"gif", @"jpeg", nil] objectEnumerator]; + NSString* allowedExt; + while ((allowedExt = [tagEnumerator nextObject])) + { + if ([ext caseInsensitiveCompare:allowedExt] == NSOrderedSame) + { + return YES; + } + } + + return NO; +} + +@end diff --git a/Mac/PostModel.h b/Mac/PostModel.h new file mode 100644 index 0000000..39eaef9 --- /dev/null +++ b/Mac/PostModel.h @@ -0,0 +1,28 @@ +// +// PostModel.h +// bungloo +// +// Created by Jeena on 10.01.11. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import +#import + +@interface PostModel : NSObject { + NSString *text; + NSString *inReplyTostatusId; + NSString *inReplyToEntity; + CLLocation *location; + NSString *imageFilePath; + BOOL isPrivate; +} + +@property (nonatomic, retain) NSString *text; +@property (nonatomic, retain) NSString *inReplyTostatusId; +@property (nonatomic, retain) NSString *inReplyToEntity; +@property (nonatomic, retain) CLLocation *location; +@property (nonatomic, retain) NSString *imageFilePath; +@property (nonatomic) BOOL isPrivate; + +@end diff --git a/Mac/PostModel.m b/Mac/PostModel.m new file mode 100644 index 0000000..b62c093 --- /dev/null +++ b/Mac/PostModel.m @@ -0,0 +1,26 @@ +// +// PostModel.m +// bungloo +// +// Created by Jeena on 10.01.11. +// Copyright 2011 __MyCompanyName__. All rights reserved. +// + +#import "PostModel.h" + + +@implementation PostModel + +@synthesize text, inReplyTostatusId, inReplyToEntity, location, imageFilePath, isPrivate; + +- (void)dealloc +{ + [text release]; + [inReplyTostatusId release]; + [inReplyToEntity release]; + [location release]; + [imageFilePath release]; + [super dealloc]; +} + +@end diff --git a/Mac/Sparkle.framework/Headers b/Mac/Sparkle.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/Mac/Sparkle.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/Mac/Sparkle.framework/Resources b/Mac/Sparkle.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Mac/Sparkle.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Mac/Sparkle.framework/Sparkle b/Mac/Sparkle.framework/Sparkle new file mode 120000 index 0000000..b2c5273 --- /dev/null +++ b/Mac/Sparkle.framework/Sparkle @@ -0,0 +1 @@ +Versions/Current/Sparkle \ No newline at end of file diff --git a/Mac/Sparkle.framework/Versions/A/Headers/SUAppcast.h b/Mac/Sparkle.framework/Versions/A/Headers/SUAppcast.h new file mode 100644 index 0000000..171148a --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Headers/SUAppcast.h @@ -0,0 +1,33 @@ +// +// SUAppcast.h +// Sparkle +// +// Created by Andy Matuschak on 3/12/06. +// Copyright 2006 Andy Matuschak. All rights reserved. +// + +#ifndef SUAPPCAST_H +#define SUAPPCAST_H + +@class SUAppcastItem; +@interface SUAppcast : NSObject { + NSArray *items; + NSString *userAgentString; + id delegate; + NSMutableData *incrementalData; +} + +- (void)fetchAppcastFromURL:(NSURL *)url; +- (void)setDelegate:delegate; +- (void)setUserAgentString:(NSString *)userAgentString; + +- (NSArray *)items; + +@end + +@interface NSObject (SUAppcastDelegate) +- (void)appcastDidFinishLoading:(SUAppcast *)appcast; +- (void)appcast:(SUAppcast *)appcast failedToLoadWithError:(NSError *)error; +@end + +#endif diff --git a/Mac/Sparkle.framework/Versions/A/Headers/SUAppcastItem.h b/Mac/Sparkle.framework/Versions/A/Headers/SUAppcastItem.h new file mode 100644 index 0000000..f2d128c --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Headers/SUAppcastItem.h @@ -0,0 +1,47 @@ +// +// SUAppcastItem.h +// Sparkle +// +// Created by Andy Matuschak on 3/12/06. +// Copyright 2006 Andy Matuschak. All rights reserved. +// + +#ifndef SUAPPCASTITEM_H +#define SUAPPCASTITEM_H + +@interface SUAppcastItem : NSObject { + NSString *title; + NSDate *date; + NSString *itemDescription; + + NSURL *releaseNotesURL; + + NSString *DSASignature; + NSString *minimumSystemVersion; + + NSURL *fileURL; + NSString *versionString; + NSString *displayVersionString; + + NSDictionary *propertiesDictionary; +} + +// Initializes with data from a dictionary provided by the RSS class. +- initWithDictionary:(NSDictionary *)dict; + +- (NSString *)title; +- (NSString *)versionString; +- (NSString *)displayVersionString; +- (NSDate *)date; +- (NSString *)itemDescription; +- (NSURL *)releaseNotesURL; +- (NSURL *)fileURL; +- (NSString *)DSASignature; +- (NSString *)minimumSystemVersion; + +// Returns the dictionary provided in initWithDictionary; this might be useful later for extensions. +- (NSDictionary *)propertiesDictionary; + +@end + +#endif diff --git a/Mac/Sparkle.framework/Versions/A/Headers/SUUpdater.h b/Mac/Sparkle.framework/Versions/A/Headers/SUUpdater.h new file mode 100644 index 0000000..e5b5081 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Headers/SUUpdater.h @@ -0,0 +1,118 @@ +// +// SUUpdater.h +// Sparkle +// +// Created by Andy Matuschak on 1/4/06. +// Copyright 2006 Andy Matuschak. All rights reserved. +// + +#ifndef SUUPDATER_H +#define SUUPDATER_H + +#import + +@class SUUpdateDriver, SUAppcastItem, SUHost, SUAppcast; +@interface SUUpdater : NSObject { + NSTimer *checkTimer; + SUUpdateDriver *driver; + + SUHost *host; + IBOutlet id delegate; +} + ++ (SUUpdater *)sharedUpdater; ++ (SUUpdater *)updaterForBundle:(NSBundle *)bundle; +- (NSBundle *)hostBundle; + +- (void)setDelegate:(id)delegate; +- delegate; + +- (void)setAutomaticallyChecksForUpdates:(BOOL)automaticallyChecks; +- (BOOL)automaticallyChecksForUpdates; + +- (void)setUpdateCheckInterval:(NSTimeInterval)interval; +- (NSTimeInterval)updateCheckInterval; + +- (void)setFeedURL:(NSURL *)feedURL; +- (NSURL *)feedURL; + +- (void)setSendsSystemProfile:(BOOL)sendsSystemProfile; +- (BOOL)sendsSystemProfile; + +- (void)setAutomaticallyDownloadsUpdates:(BOOL)automaticallyDownloadsUpdates; +- (BOOL)automaticallyDownloadsUpdates; + +// This IBAction is meant for a main menu item. Hook up any menu item to this action, +// and Sparkle will check for updates and report back its findings verbosely. +- (IBAction)checkForUpdates:sender; + +// This kicks off an update meant to be programmatically initiated. That is, it will display no UI unless it actually finds an update, +// in which case it proceeds as usual. If the fully automated updating is turned on, however, this will invoke that behavior, and if an +// update is found, it will be downloaded and prepped for installation. +- (void)checkForUpdatesInBackground; + +// Date of last update check. Returns null if no check has been performed. +- (NSDate*)lastUpdateCheckDate; + +// This begins a "probing" check for updates which will not actually offer to update to that version. The delegate methods, though, +// (up to updater:didFindValidUpdate: and updaterDidNotFindUpdate:), are called, so you can use that information in your UI. +- (void)checkForUpdateInformation; + +// Call this to appropriately schedule or cancel the update checking timer according to the preferences for time interval and automatic checks. This call does not change the date of the next check, but only the internal NSTimer. +- (void)resetUpdateCycle; + +- (BOOL)updateInProgress; +@end + +@interface NSObject (SUUpdaterDelegateInformalProtocol) +// This method allows you to add extra parameters to the appcast URL, potentially based on whether or not Sparkle will also be sending along the system profile. This method should return an array of dictionaries with keys: "key", "value", "displayKey", "displayValue", the latter two being specifically for display to the user. +- (NSArray *)feedParametersForUpdater:(SUUpdater *)updater sendingSystemProfile:(BOOL)sendingProfile; + +// Use this to override the default behavior for Sparkle prompting the user about automatic update checks. +- (BOOL)updaterShouldPromptForPermissionToCheckForUpdates:(SUUpdater *)bundle; + +// Implement this if you want to do some special handling with the appcast once it finishes loading. +- (void)updater:(SUUpdater *)updater didFinishLoadingAppcast:(SUAppcast *)appcast; + +// If you're using special logic or extensions in your appcast, implement this to use your own logic for finding +// a valid update, if any, in the given appcast. +- (SUAppcastItem *)bestValidUpdateInAppcast:(SUAppcast *)appcast forUpdater:(SUUpdater *)bundle; + +// Sent when a valid update is found by the update driver. +- (void)updater:(SUUpdater *)updater didFindValidUpdate:(SUAppcastItem *)update; + +// Sent when a valid update is not found. +- (void)updaterDidNotFindUpdate:(SUUpdater *)update; + +// Sent immediately before installing the specified update. +- (void)updater:(SUUpdater *)updater willInstallUpdate:(SUAppcastItem *)update; + +// Return YES to delay the relaunch until you do some processing; invoke the given NSInvocation to continue. +- (BOOL)updater:(SUUpdater *)updater shouldPostponeRelaunchForUpdate:(SUAppcastItem *)update untilInvoking:(NSInvocation *)invocation; + +// Called immediately before relaunching. +- (void)updaterWillRelaunchApplication:(SUUpdater *)updater; + +// This method allows you to provide a custom version comparator. +// If you don't implement this method or return nil, the standard version comparator will be used. +- (id )versionComparatorForUpdater:(SUUpdater *)updater; + +// Returns the path which is used to relaunch the client after the update is installed. By default, the path of the host bundle. +- (NSString *)pathToRelaunchForUpdater:(SUUpdater *)updater; + +@end + +// Define some minimum intervals to avoid DOS-like checking attacks. These are in seconds. +#ifdef DEBUG +#define SU_MIN_CHECK_INTERVAL 60 +#else +#define SU_MIN_CHECK_INTERVAL 60*60 +#endif + +#ifdef DEBUG +#define SU_DEFAULT_CHECK_INTERVAL 60 +#else +#define SU_DEFAULT_CHECK_INTERVAL 60*60*24 +#endif + +#endif diff --git a/Mac/Sparkle.framework/Versions/A/Headers/SUVersionComparisonProtocol.h b/Mac/Sparkle.framework/Versions/A/Headers/SUVersionComparisonProtocol.h new file mode 100644 index 0000000..d9ac619 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Headers/SUVersionComparisonProtocol.h @@ -0,0 +1,27 @@ +// +// SUVersionComparisonProtocol.h +// Sparkle +// +// Created by Andy Matuschak on 12/21/07. +// Copyright 2007 Andy Matuschak. All rights reserved. +// + +#ifndef SUVERSIONCOMPARISONPROTOCOL_H +#define SUVERSIONCOMPARISONPROTOCOL_H + +/*! + @protocol + @abstract Implement this protocol to provide version comparison facilities for Sparkle. +*/ +@protocol SUVersionComparison + +/*! + @method + @abstract An abstract method to compare two version strings. + @discussion Should return NSOrderedAscending if b > a, NSOrderedDescending if b < a, and NSOrderedSame if they are equivalent. +*/ +- (NSComparisonResult)compareVersion:(NSString *)versionA toVersion:(NSString *)versionB; + +@end + +#endif diff --git a/Mac/Sparkle.framework/Versions/A/Headers/Sparkle.h b/Mac/Sparkle.framework/Versions/A/Headers/Sparkle.h new file mode 100644 index 0000000..08dd577 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Headers/Sparkle.h @@ -0,0 +1,21 @@ +// +// Sparkle.h +// Sparkle +// +// Created by Andy Matuschak on 3/16/06. (Modified by CDHW on 23/12/07) +// Copyright 2006 Andy Matuschak. All rights reserved. +// + +#ifndef SPARKLE_H +#define SPARKLE_H + +// This list should include the shared headers. It doesn't matter if some of them aren't shared (unless +// there are name-space collisions) so we can list all of them to start with: + +#import + +#import +#import +#import + +#endif diff --git a/Mac/Sparkle.framework/Versions/A/Resources/Info.plist b/Mac/Sparkle.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..c7f277d --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + Sparkle + CFBundleIdentifier + org.andymatuschak.Sparkle + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Sparkle + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.5 Beta 6 + CFBundleSignature + ???? + CFBundleVersion + 313 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/License.txt b/Mac/Sparkle.framework/Versions/A/Resources/License.txt new file mode 100644 index 0000000..20466c4 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/License.txt @@ -0,0 +1,7 @@ +Copyright (c) 2006 Andy Matuschak + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Mac/Sparkle.framework/Versions/A/Resources/SUModelTranslation.plist b/Mac/Sparkle.framework/Versions/A/Resources/SUModelTranslation.plist new file mode 100644 index 0000000..92ef947 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/SUModelTranslation.plist @@ -0,0 +1,174 @@ + + + + + ADP2,1 + Developer Transition Kit + MacBook1,1 + MacBook (Core Duo) + MacBook2,1 + MacBook (Core 2 Duo) + MacBook4,1 + MacBook (Core 2 Duo Feb 2008) + MacBookAir1,1 + MacBook Air (January 2008) + MacBookPro1,1 + MacBook Pro Core Duo (15-inch) + MacBookPro1,2 + MacBook Pro Core Duo (17-inch) + MacBookPro2,1 + MacBook Pro Core 2 Duo (17-inch) + MacBookPro2,2 + MacBook Pro Core 2 Duo (15-inch) + MacBookPro3,1 + MacBook Pro Core 2 Duo (15-inch LED, Core 2 Duo) + MacBookPro3,2 + MacBook Pro Core 2 Duo (17-inch HD, Core 2 Duo) + MacBookPro4,1 + MacBook Pro (Core 2 Duo Feb 2008) + MacPro1,1 + Mac Pro (four-core) + MacPro2,1 + Mac Pro (eight-core) + MacPro3,1 + Mac Pro (January 2008 4- or 8- core "Harpertown") + Macmini1,1 + Mac Mini (Core Solo/Duo) + PowerBook1,1 + PowerBook G3 + PowerBook2,1 + iBook G3 + PowerBook2,2 + iBook G3 (FireWire) + PowerBook2,3 + iBook G3 + PowerBook2,4 + iBook G3 + PowerBook3,1 + PowerBook G3 (FireWire) + PowerBook3,2 + PowerBook G4 + PowerBook3,3 + PowerBook G4 (Gigabit Ethernet) + PowerBook3,4 + PowerBook G4 (DVI) + PowerBook3,5 + PowerBook G4 (1GHz / 867MHz) + PowerBook4,1 + iBook G3 (Dual USB, Late 2001) + PowerBook4,2 + iBook G3 (16MB VRAM) + PowerBook4,3 + iBook G3 Opaque 16MB VRAM, 32MB VRAM, Early 2003) + PowerBook5,1 + PowerBook G4 (17 inch) + PowerBook5,2 + PowerBook G4 (15 inch FW 800) + PowerBook5,3 + PowerBook G4 (17-inch 1.33GHz) + PowerBook5,4 + PowerBook G4 (15 inch 1.5/1.33GHz) + PowerBook5,5 + PowerBook G4 (17-inch 1.5GHz) + PowerBook5,6 + PowerBook G4 (15 inch 1.67GHz/1.5GHz) + PowerBook5,7 + PowerBook G4 (17-inch 1.67GHz) + PowerBook5,8 + PowerBook G4 (Double layer SD, 15 inch) + PowerBook5,9 + PowerBook G4 (Double layer SD, 17 inch) + PowerBook6,1 + PowerBook G4 (12 inch) + PowerBook6,2 + PowerBook G4 (12 inch, DVI) + PowerBook6,3 + iBook G4 + PowerBook6,4 + PowerBook G4 (12 inch 1.33GHz) + PowerBook6,5 + iBook G4 (Early-Late 2004) + PowerBook6,7 + iBook G4 (Mid 2005) + PowerBook6,8 + PowerBook G4 (12 inch 1.5GHz) + PowerMac1,1 + Power Macintosh G3 (Blue & White) + PowerMac1,2 + Power Macintosh G4 (PCI Graphics) + PowerMac10,1 + Mac Mini G4 + PowerMac10,2 + Mac Mini (Late 2005) + PowerMac11,2 + Power Macintosh G5 (Late 2005) + PowerMac12,1 + iMac G5 (iSight) + PowerMac2,1 + iMac G3 (Slot-loading CD-ROM) + PowerMac2,2 + iMac G3 (Summer 2000) + PowerMac3,1 + Power Macintosh G4 (AGP Graphics) + PowerMac3,2 + Power Macintosh G4 (AGP Graphics) + PowerMac3,3 + Power Macintosh G4 (Gigabit Ethernet) + PowerMac3,4 + Power Macintosh G4 (Digital Audio) + PowerMac3,5 + Power Macintosh G4 (Quick Silver) + PowerMac3,6 + Power Macintosh G4 (Mirrored Drive Door) + PowerMac4,1 + iMac G3 (Early/Summer 2001) + PowerMac4,2 + iMac G4 (Flat Panel) + PowerMac4,4 + eMac + PowerMac4,5 + iMac G4 (17-inch Flat Panel) + PowerMac5,1 + Power Macintosh G4 Cube + PowerMac6,1 + iMac G4 (USB 2.0) + PowerMac6,3 + iMac G4 (20-inch Flat Panel) + PowerMac6,4 + eMac (USB 2.0, 2005) + PowerMac7,2 + Power Macintosh G5 + PowerMac7,3 + Power Macintosh G5 + PowerMac8,1 + iMac G5 + PowerMac8,2 + iMac G5 (Ambient Light Sensor) + PowerMac9,1 + Power Macintosh G5 (Late 2005) + RackMac1,1 + Xserve G4 + RackMac1,2 + Xserve G4 (slot-loading, cluster node) + RackMac3,1 + Xserve G5 + Xserve1,1 + Xserve (Intel Xeon) + Xserve2,1 + Xserve (January 2008 quad-core) + iMac1,1 + iMac G3 (Rev A-D) + iMac4,1 + iMac (Core Duo) + iMac4,2 + iMac for Education (17-inch, Core Duo) + iMac5,1 + iMac (Core 2 Duo, 17 or 20 inch, SuperDrive) + iMac5,2 + iMac (Core 2 Duo, 17 inch, Combo Drive) + iMac6,1 + iMac (Core 2 Duo, 24 inch, SuperDrive) + iMac8,1 + iMac (April 2008) + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/classes.nib new file mode 100644 index 0000000..22f13f8 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/classes.nib @@ -0,0 +1,56 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + CLASS + SUStatusController + LANGUAGE + ObjC + OUTLETS + + actionButton + NSButton + progressBar + NSProgressIndicator + + SUPERCLASS + SUWindowController + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/info.nib new file mode 100644 index 0000000..a9ac867 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 10A96 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/keyedobjects.nib new file mode 100644 index 0000000..4f1d598 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/SUStatus.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..4b1ab30 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 0000000..2e04cfa --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..6b92630 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..994d4c3 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 0000000..2e04cfa --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..b4353d2 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 0000000..5220a22 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 0000000..2e04cfa --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 0000000..b403a3e Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/Sparkle.strings b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/Sparkle.strings new file mode 100644 index 0000000..b31f928 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/de.lproj/Sparkle.strings differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..4b1ab30 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 0000000..ab36d31 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 658 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9C7010 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..7630390 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..994d4c3 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 0000000..2fb8a83 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 18 + + IBSystem Version + 10A96 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..e7e7497 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 0000000..5220a22 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 0000000..b1cd28e --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,21 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + 41 + + IBSystem Version + 10A96 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 0000000..e8dc5b8 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/Sparkle.strings b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/Sparkle.strings new file mode 100644 index 0000000..16e0787 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/en.lproj/Sparkle.strings differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..4b1ab30 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 0000000..2e04cfa --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..6b2f938 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..994d4c3 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 0000000..2e04cfa --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..c9b1e7d Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 0000000..5220a22 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 0000000..3eb7f81 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 0000000..8c54c21 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/Sparkle.strings b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/Sparkle.strings new file mode 100644 index 0000000..f83ea23 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/es.lproj/Sparkle.strings differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..4b1ab30 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 0000000..33a6020 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..4cd529a Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..994d4c3 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 0000000..d2586ea --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..65dfc95 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 0000000..5220a22 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 0000000..d2586ea --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 0000000..4b7cc90 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/Sparkle.strings b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/Sparkle.strings new file mode 100644 index 0000000..ea175ae Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/Sparkle.strings differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/fr.lproj b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/fr.lproj new file mode 120000 index 0000000..88614fe --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/fr.lproj/fr.lproj @@ -0,0 +1 @@ +/Users/andym/Development/Build Products/Release/Sparkle.framework/Resources/fr.lproj \ No newline at end of file diff --git a/Mac/Sparkle.framework/Versions/A/Resources/fr_CA.lproj b/Mac/Sparkle.framework/Versions/A/Resources/fr_CA.lproj new file mode 120000 index 0000000..88614fe --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/fr_CA.lproj @@ -0,0 +1 @@ +/Users/andym/Development/Build Products/Release/Sparkle.framework/Resources/fr.lproj \ No newline at end of file diff --git a/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..4b1ab30 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 0000000..2e04cfa --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..15ba8f4 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..994d4c3 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 0000000..2e04cfa --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..2984064 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 0000000..5220a22 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 0000000..c493485 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 667 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 5 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 0000000..55cc2c2 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/Sparkle.strings b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/Sparkle.strings new file mode 100644 index 0000000..5c410d0 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/it.lproj/Sparkle.strings differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..4b1ab30 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 0000000..3f09790 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,18 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..aa38f86 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..994d4c3 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 0000000..d2586ea --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..c82d358 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 0000000..5220a22 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 0000000..d2586ea --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBFramework Version + 629 + IBOldestOS + 5 + IBOpenObjects + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 0000000..ac298ce Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/Sparkle.strings b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/Sparkle.strings new file mode 100644 index 0000000..67cf535 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/nl.lproj/Sparkle.strings differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/relaunch b/Mac/Sparkle.framework/Versions/A/Resources/relaunch new file mode 100755 index 0000000..e7b96d6 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/relaunch differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..4b1ab30 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 0000000..2b3d425 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..1d4655c Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..994d4c3 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,67 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + CLASS + NSApplication + LANGUAGE + ObjC + SUPERCLASS + NSResponder + + + ACTIONS + + installUpdate + id + remindMeLater + id + skipThisVersion + id + + CLASS + SUUpdateAlert + LANGUAGE + ObjC + OUTLETS + + delegate + id + description + NSTextField + releaseNotesView + WebView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 0000000..2b3d425 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..103b1cf Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 0000000..0f776c8 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + NSObject + LANGUAGE + ObjC + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 0000000..5132e29 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,18 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + IBSystem Version + 9E17 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 0000000..c09d9e7 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/Sparkle.strings b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/Sparkle.strings new file mode 100644 index 0000000..f3ff9d8 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/ru.lproj/Sparkle.strings differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..4b1ab30 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/classes.nib @@ -0,0 +1,50 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + doNotInstall + id + installLater + id + installNow + id + + CLASS + SUAutomaticUpdateAlert + LANGUAGE + ObjC + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/info.nib new file mode 100644 index 0000000..c5a067e --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 10A96 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..53cb91a Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUAutomaticUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/classes.nib new file mode 100644 index 0000000..018710a --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/classes.nib @@ -0,0 +1,39 @@ +{ + IBClasses = ( + { + CLASS = FirstResponder; + LANGUAGE = ObjC; + SUPERCLASS = NSObject; + }, + { + CLASS = NSApplication; + LANGUAGE = ObjC; + SUPERCLASS = NSResponder; + }, + { + CLASS = NSObject; + LANGUAGE = ObjC; + }, + { + ACTIONS = { + installUpdate = id; + remindMeLater = id; + skipThisVersion = id; + }; + CLASS = SUUpdateAlert; + LANGUAGE = ObjC; + OUTLETS = { + delegate = id; + description = NSTextField; + releaseNotesView = WebView; + }; + SUPERCLASS = SUWindowController; + }, + { + CLASS = SUWindowController; + LANGUAGE = ObjC; + SUPERCLASS = NSWindowController; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/info.nib new file mode 100644 index 0000000..6b787d4 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/info.nib @@ -0,0 +1,18 @@ + + + + + IBDocumentLocation + 69 14 356 240 0 0 1280 778 + IBFramework Version + 489.0 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBSystem Version + 9D34 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/keyedobjects.nib new file mode 100644 index 0000000..7e6d490 Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdateAlert.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/classes.nib b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/classes.nib new file mode 100644 index 0000000..5220a22 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/classes.nib @@ -0,0 +1,59 @@ + + + + + IBClasses + + + CLASS + SUWindowController + LANGUAGE + ObjC + SUPERCLASS + NSWindowController + + + ACTIONS + + finishPrompt + id + toggleMoreInfo + id + + CLASS + SUUpdatePermissionPrompt + LANGUAGE + ObjC + OUTLETS + + delegate + id + descriptionTextField + NSTextField + moreInfoButton + NSButton + moreInfoView + NSView + + SUPERCLASS + SUWindowController + + + CLASS + FirstResponder + LANGUAGE + ObjC + SUPERCLASS + NSObject + + + CLASS + NSObject + LANGUAGE + ObjC + + + IBVersion + 1 + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/info.nib b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/info.nib new file mode 100644 index 0000000..c5a067e --- /dev/null +++ b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/info.nib @@ -0,0 +1,20 @@ + + + + + IBFramework Version + 670 + IBLastKnownRelativeProjectPath + ../Sparkle.xcodeproj + IBOldestOS + 5 + IBOpenObjects + + 6 + + IBSystem Version + 10A96 + targetFramework + IBCocoaFramework + + diff --git a/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib new file mode 100644 index 0000000..64babac Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/SUUpdatePermissionPrompt.nib/keyedobjects.nib differ diff --git a/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/Sparkle.strings b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/Sparkle.strings new file mode 100644 index 0000000..b676a4f Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Resources/sv.lproj/Sparkle.strings differ diff --git a/Mac/Sparkle.framework/Versions/A/Sparkle b/Mac/Sparkle.framework/Versions/A/Sparkle new file mode 100755 index 0000000..0db0a8f Binary files /dev/null and b/Mac/Sparkle.framework/Versions/A/Sparkle differ diff --git a/Mac/Sparkle.framework/Versions/Current b/Mac/Sparkle.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Mac/Sparkle.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Mac/TB_SendTemplate.png b/Mac/TB_SendTemplate.png new file mode 100644 index 0000000..b2602fe Binary files /dev/null and b/Mac/TB_SendTemplate.png differ diff --git a/Mac/ViewDelegate.h b/Mac/ViewDelegate.h new file mode 100644 index 0000000..689b094 --- /dev/null +++ b/Mac/ViewDelegate.h @@ -0,0 +1,19 @@ +// +// ViewDelegate.h +// bungloo +// +// Created by Jeena on 15.04.10. +// Licence: BSD (see attached LICENCE.txt file). +// + +#import +#import +#import "Constants.h" + +@interface ViewDelegate : NSObject { + WebView *timelineView; WebView *oauthView; +} + +@property (nonatomic, assign) WebView *timelineView;@property (nonatomic, assign) WebView *oauthView; + +@end diff --git a/Mac/ViewDelegate.m b/Mac/ViewDelegate.m new file mode 100644 index 0000000..c10a6ad --- /dev/null +++ b/Mac/ViewDelegate.m @@ -0,0 +1,123 @@ +// +// ViewDelegate.m +// bungloo +// +// Created by Jeena on 15.04.10. +// Licence: BSD (see attached LICENCE.txt file). +// + +#import "ViewDelegate.h" + + +@implementation ViewDelegate + +@synthesize timelineView, oauthView; + +- (void)webView:(WebView *)sender addMessageToConsole:(NSDictionary *)message { + + if (![message isKindOfClass:[NSDictionary class]]) return; + + NSString *viewName = @"TimelineView"; + if (sender == oauthView) viewName = @"OauthView"; + + NSLog(@"js<%@>: %@:%@: %@", + viewName, + [[message objectForKey:@"sourceURL"] lastPathComponent], + [message objectForKey:@"lineNumber"], + [message objectForKey:@"message"] + ); +} + +- (void)webView:(WebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame { + NSString *viewName = @"TimelineView"; + if (sender == oauthView) viewName = @"OauthView"; + + NSLog(@"jsa<%@>: %@", viewName, message); +} + +- (BOOL)webView:(WebView *)sender runJavaScriptConfirmPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame { + NSInteger result = NSRunCriticalAlertPanel(NSLocalizedString(@"Bungloo", @""), // title + message, // message + NSLocalizedString(@"OK", @""), // default button + NSLocalizedString(@"Cancel", @""), // alt button + nil); + return NSAlertDefaultReturn == result; + return NO; +} + +- (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id )listener { + + NSArray *frames = [NSArray arrayWithObjects:timelineView.mainFrame, oauthView.mainFrame, nil]; + + // If it is clicked from one of the views the open default browser + if ([frames indexOfObject:frame] != NSNotFound) { + [listener ignore]; + [[NSWorkspace sharedWorkspace] openURL:[request URL]]; + } else { // otherwies load the iframe stuff like YouTube or vimeo + [listener use]; + } +} + +- (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame { + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *pathToJsPlugin = [@"~/Library/Application Support/bungloo/Plugin.js" stringByExpandingTildeInPath]; + NSString *pathToCssPlugin = [@"~/Library/Application Support/bungloo/Plugin.css" stringByExpandingTildeInPath]; + + if([fileManager fileExistsAtPath:pathToCssPlugin]) + { + [sender stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"setTimeout(function() { loadCssPlugin('file://localhost%@') }, 1000);", pathToCssPlugin]]; + } + + if([fileManager fileExistsAtPath:pathToJsPlugin]) + { + [sender stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"setTimeout(function() { loadJsPlugin('file://localhost%@') }, 1000);", pathToJsPlugin]]; + } + + [sender stringByEvaluatingJavaScriptFromString:@"var OS_TYPE = 'mac';"]; + + if (sender == oauthView) { + + [oauthView stringByEvaluatingJavaScriptFromString:@"function HostAppGo() { start('oauth') }"]; + + } else { + + [sender stringByEvaluatingJavaScriptFromString:@"function HostAppGo() { start('timeline') }"]; + } +} + +- (NSArray *)webView:(WebView *)sender contextMenuItemsForElement:(NSDictionary *)element defaultMenuItems:(NSArray *)defaultMenuItems +{ + // FIXME + /* + NSMutableArray *menuItems = [NSMutableArray arrayWithArray:defaultMenuItems]; + + for (NSMenuItem*item in defaultMenuItems) { + if ([[item title] isEqualToString:@"Reload"]) { + //[item setAction:@selector(reload:)]; + //[item setTarget:self]; + } else { + [menuItems addObject:item]; + } + }*/ + + return defaultMenuItems; +} + +- (void)reload:(id)sender { + [timelineView stringByEvaluatingJavaScriptFromString:@"bungloo.timeline.getNewData();"]; +} + +- (NSString *)pluginURL +{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *pathToPlugin = [@"~/Library/Application Support/Bungloo/Plugin.js" stringByExpandingTildeInPath]; + + if([fileManager fileExistsAtPath:pathToPlugin]) + { + return [NSString stringWithFormat:@"%@", [NSURL fileURLWithPath:pathToPlugin]]; + } + return nil; +} + +@end diff --git a/Mac/deploy.sh b/Mac/deploy.sh deleted file mode 100755 index 44841e9..0000000 --- a/Mac/deploy.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -HERE=`pwd` -TMP="/tmp" - -rm -rf Bungloo.app -rm -rf $TMP/bungloo -mkdir $TMP/bungloo -cp -r ../Qt/* $TMP/bungloo -cp -r ../WebKit $TMP/bungloo -cp -r ../images $TMP/bungloo -cp Icon.icns $TMP/bungloo/images -cp setup.py $TMP/bungloo -cp Info.plist $TMP/bungloo -cd $TMP/bungloo -python setup.py py2app -mv $TMP/bungloo/dist/Bungloo.app $HERE -cd $HERE -rm -rf $TMP/bungloo -Bungloo.app/Contents/MacOS/Bungloo \ No newline at end of file diff --git a/Mac/main.m b/Mac/main.m new file mode 100644 index 0000000..75ec058 --- /dev/null +++ b/Mac/main.m @@ -0,0 +1,14 @@ +// +// main.m +// bungloo +// +// Created by Jeena on 16.04.10. +// Licence: BSD (see attached LICENCE.txt file). +// + +#import + +int main(int argc, char *argv[]) +{ + return NSApplicationMain(argc, (const char **) argv); +} diff --git a/Mac/publish/Appcast.xml b/Mac/publish/Appcast.xml new file mode 100755 index 0000000..548fc83 --- /dev/null +++ b/Mac/publish/Appcast.xml @@ -0,0 +1,20 @@ + + + + Bungloo's Changelog + http://jabs.nu/Bungloo/download/Appcast.xml + Most recent changes with links to updates. + en + + Version 1.1.0 + 10.5.0 + http://jabs.nu/bungloo/download/ReleaseNotes.html + Mon, 18 Feb 2013 11:33:48 +0100 + + + + diff --git a/Mac/publish/ReleaseNotes.html b/Mac/publish/ReleaseNotes.html new file mode 100644 index 0000000..4934529 --- /dev/null +++ b/Mac/publish/ReleaseNotes.html @@ -0,0 +1,225 @@ + + + + Tentia Release Notes + + + + +

Bungloo 1.2.0

+ +

Inline video for YouTube and Vimeo + inline sound for SoundCloud, sadly some buttons in the widgets still don't work but you can watch the videos and hear the music :)

+

Better handling of non square avatars

+

Bugfixes, now loading more profiles correctly

+

Multiple mentions now are added behind a /cc while responding

+

Bugfix, better handling of - in entities

+ +
+ +

Bungloo 1.1.0

+ +

Moved time ago so it is always visible

+

Implemented thumbnails for linked images and videos

+

Added a map to posts with position

+

Links now are only linked if they start with http

+

Smaller bugfixes

+ +
+ +

Bungloo 1.0.0

+ +

Automatic updade doesn't work, please download Bungloo from here: Bungloo.app.zip and then remove the old Tentia from your Applications directory.

+

Renamed the application from Tentia to Bungloo as proposed by ^nn.tent.is + (Thank you for that!). Watch OfficeHours 2013-01-22 + if you want to know why it needed to be renamed

+

Added new icon by http://www.fasticon.com

+

Smaller bugfixes

+

Allowing empty text if location or image is present

+

Changed the look of names

+

Shows in profile if entity is following you

+

Added "follows since 'timeago'" to following/followers lists, thanks for the + pullrequest ^nn.tent.is

+

Temporarily highlights a reposted post

+ + +
+ +

Tentia 0.6.2

+ +

Added possibility to show followings and followers to profile view. Just click on the number.

+ +
+ +

Tentia 0.6.1

+ +

Removed shaddows from posts like discussed with ^kevinkleinman.tent.is, more UI changes to come

+

Thanks to ^nn.tent.is for fixing the bug which would send on Cmd+something

+

Smaller bugfixes.

+ +
+ +

Tentia 0.6.0

+ +

Reposts are now collected

+

Open profile is now Cmd U

+

Sending mentions read cursor, therefor you need to reauthenticate

+

Fixed entity detection which contain dot at the end

+

Profiles with no name are linked now

+

Using open street map now when clicking on the pin

+ +
+ +

Tentia 0.5.4

+ +

Fixed critical bug which prevented finding mentions in text

+ +
+ +

Tentia 0.5.3

+ +

Fixed problem where deleted posts weren't removed from Mentions

+

Fixed problem with localStorage on 10.7

+

Showind photos now on the profile

+

Smaller bugfixes

+ +
+ +

Tentia 0.5.2

+ +

Click on avatar opens profile

+

Added possibility to post photos (not available on basic tent.is plan)

+

Bugfixes

+

Changed app name to "Tentia on OS X", therefor you need to reauthenticate.

+ +
+ +

Tentia 0.5.1

+ +

Implemented private posts

+

Implemented cache

+

Support for HTML <link> element

+

Clicking on dock icon opens main window

+

Fixed conversation view loading posts

+

Repost is now mentioning the original post

+

Several bugfixes

+ +
+ +

Tentia 0.5.0

+ +

Added "Send" button to "New Post" window

+

Added Profile view

+

Added follow and unfollow possibility

+ +
+ +

Tentia 0.4.2

+ +

Removed Photo post type because the Tent protocol in version 0.1.0 does not quite support it yet

+

Implemented showing and making reposts

+ +
+ +

Tentia 0.4.1

+ +

Fixed problem where you couldn't log in again after you logged out.

+ +
+ +

Tentia 0.4.0

+ +

Implemented Photo post type, you can now upload a photo and see the photos others uploaded

+ +
+ +

Tentia 0.3.1

+ +

Security update

+

Thanks to ^epirat.tent.is the secret key is now saved in the OS X Keychain instead of the NSUserDefaults file

+ +
+ +

Tentia 0.3.0

+ +

Implemented delete own posts

+

Implemented remove deleted posts

+

Added a JS and CSS Plugin API

+

Implemented adding location to post

+

Implemented blue right border if you're mentioned in a post

+

Bugfixes

+ +
+ +

Tentia 0.2.4

+ +

Activeted spell checking

+

Fixed problem where Tentia would stop updating

+

Added a better detection of links in status texts

+

Hashed are linked to skate.io now

+ +
+ +

Tentia 0.2.3

+ +

Fixed problem where you couldn't login with a https entity

+

Moved Mentions and Timeline from File to Window menu item

+ +
+ +

Tentia 0.2.2

+ +

Resizable "New Post" window

+

Better authentication guidance

+

Fixed broken Window menu

+

Enter now works in "Nes Post" and is visible in all views

+

Bugfixes

+ +
+ +

Tentia 0.2.1

+ +

Sadly the automatic update from 0.2.0 will not work. Please download + this version manually from + HERE.

+

Working on OS X < 10.8 again

+

Added growl support

+

Bugfixes

+

Moved reply icon to left so it is easier to use when the scrollbar is shown

+

Login with the [Login] button now works

+

Fixed automatic updates so it will work next time again.

+ +
+ +

Tentia 0.2.0

+ +

Bugfixes

+

Implemented Notification Center

+

Implemented new Conversation view

+

Needs to reauthenticate to get all needed permissions

+ +
+ +

Tentia 0.1.2

+

Bugfixes

+

Mentions now appear as realnames

+ +
+ +

Tentia 0.1.1

+

Bugfixes

+

Changed to send on Cmd+Enter.

+ +
+ +

Tentia 0.1.0

+

First attempt to rewrite the old Twitter client Twittia to a new and shiny Tent client Tentia.

+ + + \ No newline at end of file diff --git a/Mac/publish/dsa_pub.pem b/Mac/publish/dsa_pub.pem new file mode 100644 index 0000000..4c959f3 --- /dev/null +++ b/Mac/publish/dsa_pub.pem @@ -0,0 +1,20 @@ +-----BEGIN PUBLIC KEY----- +MIIDPDCCAi4GByqGSM44BAEwggIhAoIBAQDjho3c9LB9TBv/wUQSegtiD2Q/YFjK +HvJH2ndtw2MIwd9iLA4JgXuZAZHpIa+YV7vU97TCvdRmO50VkfULkRona2SjE8lR +oK3VMOkJNGlAK0MfNgDF3/KcI7W6wTZRq/QLLI9Hi1oUpfheDCrrONyvHhCRW5UD +Rm/1Y/TltWfvDi2XmzvVFc9ISnuWoAntzp0IshWeAkcpDLbXJ3u9GudVAHeowEps ++BlMHMrzKPyvviRp0skJkmYvDpZn1YI9WhI4a65hPvgGO7a0/bgc1WbI6nR9mx6f +v+L37eqXoAJ+jrd2BaxD73BH7gBidO3xEYP0oUAxi1xkh2t587yyPU9lAhUAkKxj +3QWYyr+bYg6PDQyx2XpU+hcCggEBAJjhPOB+yLjbobEKJLzdjYujO0XMKVwej6k9 +14lCems95gwjWVS8t8rLAEYcheUPsz4rAid0ONCRQYbWmMBksv6AuXYH/qQM0BcB +DXtXnTRjUkDHCyWw+/QnkiQ+oHrzsZHPO1j+gsLOvZw2dfC1DUHHqsqaW1Oq8Xu9 +q+slmwbjTuymsbgfBJ27P09PU+FM0VNVQTCEXfZTMlDsCl6o19QmRbCLAqY0VhKZ +qPeL0atvdkaczDrNReZYRHcCfa9sO74Kt/m10UW7vEL5bIjYTN7kWvLh5HAuMvZo +Ta77PJpD0X0HbPUrX0/2YXZchxt3is1Tfy03T9aO4iWE+0Qy6wYDggEGAAKCAQEA +4AxqBHt4LMlsK330/0YXhyKYJEBjDHftz8vFuyq7Zob0t5euDExqtkjnDTo9BD/m +4tOE3/12IHL8kPpB0augGHONyoCO7Fdm+CR+mWNMqg2qo5mdPxEzP74WFrryhvh3 +z/GMhBPfZ/qSbfOvI9snc2KS6Pi34L+Je1UiYt8+gmN/uF/cUTWIkOUavI6AuGIB +oCkWGpEYjAYfZkR80/pKNQq2qLc9hiUAj1VpY5B6pxlelmos+/F62Je+E6Fd1VZN +cJfvL2kp/9bPU35cye4/FGkrW94DgRBw3IpAVrnwjnglJn2JUr7BySLO7PhFfTvO +ZbWeowFp6qKpOugZ7kS//w== +-----END PUBLIC KEY----- diff --git a/Mac/publish/publish.rb b/Mac/publish/publish.rb new file mode 100755 index 0000000..b036fb8 --- /dev/null +++ b/Mac/publish/publish.rb @@ -0,0 +1,56 @@ +#!/usr/bin/env ruby -wKU +require 'time' + +def test var, message + unless var + puts message + exit + end +end + +path = File.dirname File.expand_path(__FILE__) +mac_path = File.expand_path(path + "/..") +release_path = mac_path + "/build/Release/" + +version = `defaults read \"#{release_path}/Bungloo.app/Contents/Info\" CFBundleVersion`.gsub(/\n/,'') +length = `stat -f %z \"#{release_path}/Bungloo.app.zip\"`.gsub(/\n/,'') +signature = `ruby \"#{mac_path}/../../Sparkle\ 1.5b6/Extras/Signing Tools/sign_update.rb\" \"#{release_path}/Bungloo.app.zip\" \"#{mac_path}/publish/dsa_priv.pem\"`.gsub(/\n/,'') + +test version, "Couldn't find version" +test length, "Couldn't find length" +test signature, "Couldn't find signature" + +unless File.exists? "#{release_path}/Bungloo.app/Contents/Resources/dsa_pub.pem" + puts "#{release_path}/Bungloo.app/Contents/dsa_pub.pem" + exit +end + +xml = < + + + Bungloo's Changelog + http://jabs.nu/Bungloo/download/Appcast.xml + Most recent changes with links to updates. + en + + Version #{version} + 10.5.0 + http://jabs.nu/bungloo/download/ReleaseNotes.html + #{Time.now.rfc2822} + + + + +XML + +File.open("#{path}/Appcast.xml", 'w') {|f| f.write(xml) } +system "scp \"#{release_path}/Bungloo.app.zip\" jeena@jeena.net:~/jabs.nu/public/bungloo/download/" +system "scp \"#{path}/ReleaseNotes.html\" jeena@jeena.net:~/jabs.nu/public/bungloo/download/" +system "scp \"#{path}/Appcast.xml\" jeena@jeena.net:~/jabs.nu/public/bungloo/download/" + +puts "Done." diff --git a/Mac/setup.py b/Mac/setup.py deleted file mode 100644 index f684a7c..0000000 --- a/Mac/setup.py +++ /dev/null @@ -1,49 +0,0 @@ -""" -This is a setup.py script generated by py2applet - -Usage: - python setup.py py2app -""" - -from setuptools import setup -import os, PyQt4 - -files = [] - -for dirname, dirnames, filenames in os.walk('WebKit'): - for filename in filenames: - files += [(dirname, [os.path.join(dirname, filename)])] - -for dirname, dirnames, filenames in os.walk('images'): - for filename in filenames: - files += [(dirname, [os.path.join(dirname, filename)])] - -VERSION = "2.0.0" - -APP = ['Bungloo.py'] -OPTIONS = { - 'argv_emulation': False, - 'iconfile': 'images/Icon.icns', - 'plist': { - 'CFBundleShortVersionString': VERSION, - 'CFBundleIdentifier': "nu.jabs.apps.bungloo", - 'LSMinimumSystemVersion': "10.4", - 'CFBundleURLTypes': [ - { - 'CFBundleURLName': 'nu.jabs.apps.bungloo.handler', - 'CFBundleURLSchemes': ['bungloo'] - } - ] - }, - 'includes':['PyQt4.QtWebKit', 'PyQt4', 'PyQt4.QtCore', 'PyQt4.QtGui', 'simplejson', 'PyQt4.QtNetwork'], - 'excludes': ['PyQt4.QtDesigner', 'PyQt4.QtOpenGL', 'PyQt4.QtScript', 'PyQt4.QtSql', 'PyQt4.QtTest', 'PyQt4.QtXml', 'PyQt4.phonon'], - 'qt_plugins': 'imageformats', -} - -setup( - app=APP, - version=VERSION, - data_files=files, - options={'py2app': OPTIONS}, - setup_requires=['py2app'], -) diff --git a/Qt/SingleApplication.py b/Qt/SingleApplication.py deleted file mode 100755 index 91c8e97..0000000 --- a/Qt/SingleApplication.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python2 - -# from http://stackoverflow.com/questions/8786136/pyqt-how-to-detect-and-close-ui-if-its-already-running - -from PyQt4 import QtGui, QtCore, QtNetwork -import json - -class SingleApplication(QtGui.QApplication): - def __init__(self, argv, key): - self.bungloo = None - QtGui.QApplication.setGraphicsSystem("raster") - QtGui.QApplication.__init__(self, argv) - self._memory = QtCore.QSharedMemory(self) - self._memory.setKey(key) - if self._memory.attach(): - self._running = True - else: - self._running = False - if not self._memory.create(1): - raise RuntimeError( - self._memory.errorString().toLocal8Bit().data()) - - def isRunning(self): - return self._running - -class SingleApplicationWithMessaging(SingleApplication): - def __init__(self, argv, key): - SingleApplication.__init__(self, argv, key) - self._key = key - self._timeout = 1000 - self._server = QtNetwork.QLocalServer(self) - if not self.isRunning(): - self._server.newConnection.connect(self.handleMessage) - self._server.listen(self._key) - - def handleMessage(self): - socket = self._server.nextPendingConnection() - if socket.waitForReadyRead(self._timeout): - self.emit(QtCore.SIGNAL('messageAvailable'), - QtCore.QString.fromUtf8(socket.readAll().data())) - socket.disconnectFromServer() - else: - QtCore.qDebug(socket.errorString().toLatin1()) - - def sendMessage(self, message): - if self.isRunning(): - socket = QtNetwork.QLocalSocket(self) - socket.connectToServer(self._key, QtCore.QIODevice.WriteOnly) - if not socket.waitForConnected(self._timeout): - print(socket.errorString().toLocal8Bit().data()) - return False - socket.write(unicode(message).encode('utf-8')) - if not socket.waitForBytesWritten(self._timeout): - print(socket.errorString().toLocal8Bit().data()) - return False - socket.disconnectFromServer() - return True - return False - - def event(self, event): - if isinstance(event, QtGui.QFileOpenEvent): - url = str(event.url().toString()) - args = json.dumps([url]) - self.bungloo.handleMessage(args) - return True - -class Window(QtGui.QWidget): - def __init__(self): - QtGui.QWidget.__init__(self) - self.edit = QtGui.QLineEdit(self) - self.edit.setMinimumWidth(300) - layout = QtGui.QVBoxLayout(self) - layout.addWidget(self.edit) - - def handleMessage(self, message): - self.edit.setText(message) - -if __name__ == '__main__': - - import sys - - key = 'FOO_BAR' - - if len(sys.argv) > 1: - app = SingleApplicationWithMessaging(sys.argv, key) - if app.isRunning(): - app.sendMessage(sys.argv[1]) - sys.exit(1) - else: - app = SingleApplication(sys.argv, key) - if app.isRunning(): - print('app is already running') - sys.exit(1) - - window = Window() - app.connect(app, QtCore.SIGNAL('messageAvailable'), - window.handleMessage) - window.show() - - sys.exit(app.exec_()) \ No newline at end of file diff --git a/WebKit/css/default.css b/WebKit/css/default.css index 2d314ec..4dd168c 100644 --- a/WebKit/css/default.css +++ b/WebKit/css/default.css @@ -7,34 +7,16 @@ html, body { body { font-family: "Lucida Grande", "Open Sans", "Ubuntu", Tahoma, sans-serif; font-size: 11px; - background: #dedede center center no-repeat; -} - -body#with-sidebar { - background-image: url(../img/background.png); + background: #dedede url(../img/background.png) center center no-repeat; } a { text-decoration: none; color: #00317a; outline: 0; - outline : none; -} - -button { - background: transparent; - border: 0; - margin: 0; - padding: 4px 5px 0 5px; - outline : none; } #sidebar { - display: none; -} - -#with-sidebar #sidebar { - display: block; position: fixed; top: 0; left: 0; @@ -50,11 +32,6 @@ button { text-align: center; } -#sidebar * { - -webkit-touch-callout: none; - -webkit-user-select: none; -} - #siedebar a { color: #5b5b5b; } @@ -82,7 +59,7 @@ button { /*display: none;*/ } -#with-sidebar #content { +#content { margin-left: 62px; } @@ -92,7 +69,7 @@ ol { padding: 0; } -ol li .post, .error, header.profile { +ol li, .error, header.profile { clear: both; padding: 8px; background: #eee; @@ -109,33 +86,37 @@ ol li .post, .error, header.profile { color: red; } -#content ol > li:first-child > .post { +#content ol > li { + +} + +#content ol > li:first-child { border-top: 0; } -#content ol > li:nth-child(odd) > .post, .error, header.profile, #content #conversation-tree li.odd > .post { +#content ol > li:nth-child(odd), .error, header.profile { background: #fafafa; } -#content ol > li:nth-child(even) > .post, #content #conversation-tree li.even > .post { +#content ol > li:nth-child(even) { background: #f2f2f2; } -#content ol > li > .post:hover { - background: #dedede !important; +#content ol > li:hover { + background: #dedede; } -#content ol > li.highlighteffect > .post { +#content ol > li.highlighteffect { background-color: #FFFBD0; -webkit-transition: background-color 200ms linear; } -#content ol > li.highlighteffect-after > .post { +#content ol > li.highlighteffect-after { -webkit-transition: background-color 1000ms linear; } -#content ol > li .post:after, header.profile:after { +#content ol > li:after, header.profile:after { content: "."; display: block; clear: both; @@ -167,7 +148,7 @@ header.profile h1 + p { margin-bottom: 10px; } -.highlight > .post { +.highlight { border-right: 5px solid #f17779; } @@ -188,10 +169,6 @@ p { word-wrap: break-word; } -p + p { - padding-top: 0.5em; -} - .image { float: left; margin-left: 2px; @@ -237,39 +214,37 @@ p + p { font-weight: bold; } -li .post:hover .from { +li .from { + position: absolute; + top: -1.8em; + right: 10px; + display: none; + padding: 0.3em 0.9em; + -webkit-border-top-left-radius: 8px; + -webkit-border-top-right-radius: 8px; + -webkit-box-shadow: 0 -2px 2px rgba(0, 0, 0, 0.1); + border: 1px solid white; + border-bottom: 0; + background: #ddd; + font-size: 0.9em; +} + +li:hover .from { display: block; } -li .post .from { - position: absolute; - right: 3.5em; - display: none; - padding: 0.3em 0.9em; - background: #ddd; - font-size: 0.9em; - top: auto; - bottom: -1.8em; - z-index: 2; - -webkit-border-top-left-radius: 0; - -webkit-border-top-right-radius: 0; - -webkit-border-bottom-left-radius: 8px; - -webkit-border-bottom-right-radius: 8px; - -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.1); - border: 1px solid #b9b9b9; - border-top: 0; -} -li:last-child:not(:first-child) .post:hover .from { - top: -1.8em; - bottom: auto; - -webkit-border-top-left-radius: 8px; - -webkit-border-top-right-radius: 8px; - -webkit-border-bottom-left-radius: 0px; - -webkit-border-bottom-right-radius: 0px; - -webkit-box-shadow: 0 -2px 2px rgba(0, 0, 0, 0.1); - border: 1px solid white; - border-bottom: 0; +li:first-child:hover .from { + top: auto; + bottom: -1.8em; + z-index: 2; + -webkit-border-top-left-radius: 0; + -webkit-border-top-right-radius: 0; + -webkit-border-bottom-left-radius: 8px; + -webkit-border-bottom-right-radius: 8px; + -webkit-box-shadow: 0 2px 2px rgba(0, 0, 0, 0.1); + border: 1px solid #b9b9b9; + border-top: 0; } aside { @@ -286,7 +261,7 @@ aside { visibility: hidden; } -li .post:hover > aside .reply_to, li .post:hover > aside .repost, li .post:hover > aside .remove, li .post:hover > aside .ago:before { +li:hover aside .reply_to, li:hover aside .repost, li:hover aside .remove, li:hover aside .ago:before { visibility: visible; } @@ -313,11 +288,11 @@ li .post:hover > aside .reply_to, li .post:hover > aside .repost, li .post:hover background-position: -128px 0; } -li.mentioned .post { +li.mentioned { border-right: 5px solid #00317a; } -.mentions li.mentioned .post { +.mentions li.mentioned { border-right: 0; } @@ -397,17 +372,12 @@ li.mentioned .post { .name { font-weight: bold; - border-bottom: 1px dotted ; } .message { clear: right; } -.message a:not(.name) { - text-decoration: underline; -} - header.profile button { background: #09F; float: right; @@ -448,48 +418,10 @@ iframe { form.search { text-align: center; padding: 5px 10%; - border-bottom: 1px solid #c9c9c9; } form.search input { width: 100%; padding: 10px; font-size: 1.2em; -} - -p.noresult { - padding : 10px; - text-align : center; -} - -.new_post #sidebar, .new_post #content { display: none; } -.new_post { height: 100%; } -#new_post_container { position: absolute; border-collapse: collapse; height: 100%; width: 100%; } -#new_post_container td { position: relative; height: 90%; } -#new_post_container .text td { background: white; } -#new_post_container textarea { resize: none; box-sizing: border-box; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; background: transparent; outline: none; } -#new_post_container div { box-sizing: border-box; position: absolute; top: 0; left: 0; width: 100%; height: 100%; border: 0; background: white; color: transparent; padding: 2px; } - -#new_post_container div span { background: #D8DFEA; } -#suggestions { width: 100%; position: absolute; left: 0; bottom: 0; background: #efefef; list-style-type: none; padding: 0; margin: 0; border-top: 1px solid #ccc; } -#suggestions li { border-top: 1px solid #fefefe; border-bottom: #c9c9c9; padding: 0 0.5em; } -#suggestions strong { font-weight: normal; color: #555; } -#suggestions .active { background: #dedede; } -#suggestions .active strong { color: black; } -#status_bar { height: 1em; border-top: 1px solid #ccc; } -#status_bar p { float: right; margin: 0; padding: 0; } -#status_bar span { display: inline-block; margin: 4px 5px 0 5px; } - -#conversation-tree ol { - border-left: 1px solid #c9c9c9; - clear: both; -} - -#conversation-tree ol li { - clear: both !important; - padding-left: 14px; -} - -#conversation-tree ol li .post { - border-left: 1px solid #c9c9c9; -} +} \ No newline at end of file diff --git a/WebKit/scripts/controller/Conversation.js b/WebKit/scripts/controller/Conversation.js index 4ff204d..b488d32 100644 --- a/WebKit/scripts/controller/Conversation.js +++ b/WebKit/scripts/controller/Conversation.js @@ -1,53 +1,39 @@ define([ "helper/HostApp", "helper/Core", - "helper/APICalls", - "lib/URI", - "helper/ConversationNode" + "helper/Paths", + "lib/URI" ], -function(HostApp, Core, APICalls, URI, ConversationNode) { +function(HostApp, Core, Paths, URI) { - function Conversation(standalone) { + function Conversation() { Core.call(this); - - this.standalone = standalone; this.action = "conversation"; - this.container = document.createElement("div"); - this.container.className = this.action; this.body = document.createElement("ol"); - this.container.appendChild(this.body) + this.body.className = this.action; - document.getElementById("content").appendChild(this.container); - if(!this.standalone) this.hide(); - - // Stop loading if ESC is pressed - this.stopLoading = false; - var _this = this; - $(document).keydown(function(e) { - if (e.keyCode == 27) { // Esc - _this.stopLoading = true; - _this.makeTree(); - } - }); + document.getElementById("content").appendChild(this.body); + this.hide(); } Conversation.prototype = Object.create(Core.prototype); Conversation.prototype.show = function() { - Core.prototype.show.call(this, this.container); + Core.prototype.show.call(this, this.body); } Conversation.prototype.hide = function() { - Core.prototype.hide.call(this, this.container); + Core.prototype.hide.call(this, this.body); } Conversation.addStatus = function(status) { + this.body.appendChild(this.getStatusDOMElement(status)); } @@ -55,144 +41,108 @@ function(HostApp, Core, APICalls, URI, ConversationNode) { Conversation.prototype.showStatus = function(id, entity) { this.body.innerHTML = ""; - this.rootNode = null; - this.current_post_id = id; - this.current_entity = entity; this.append(id, entity); } - // Hack for OS X - Conversation.prototype.showStatusFromController = function() { - this.showStatus(conversationViewController.postId, conversationViewController.entity); - } - Conversation.prototype.append = function(id, entity, node, add_after) { - if(this.stopLoading) return; - var _this = this; var callback = function(resp) { - var _statuses = JSON.parse(resp.responseText); + var status = JSON.parse(resp.responseText); - for (var entity in _statuses.profiles) { - if (_statuses.profiles[entity] != null) { - bungloo.cache.profiles[entity] = _statuses.profiles[entity]; - } else { - bungloo.cache.profiles[entity] = {}; - } - } - - var status = _statuses.post; - - var dom_element = _this.getStatusDOMElement(status, _statuses.refs); - var cNode = new ConversationNode(dom_element); - dom_element.cNode = cNode; + var dom_element = _this.getStatusDOMElement(status); if (node) { - if(add_after) { // is a child of node - node.parentNode.insertBefore(dom_element, node.nextSibling); - node.cNode.addChild(cNode); - } else { // is a parent of node - node.parentNode.insertBefore(dom_element, node); - cNode.addChild(node.cNode); - } - } else { // is start node (doesn't have to be root, can have parents) + node.parentNode.insertBefore(dom_element, node); + + } else { dom_element.className = "highlight"; _this.body.appendChild(dom_element); - _this.rootNode = cNode; + _this.appendMentioned(id, entity, dom_element); } - // child posts - _this.appendMentioned(id, entity, dom_element); - - // parent posts - if(status.mentions) { - for (var i = 0; i < status.mentions.length; i++) { - var mention = status.mentions[i]; - if(mention.post) { - // don't load if it is already there - if(!document.getElementById("post-" + mention.post + "-" + _this.action)) { - _this.append(mention.post, mention.entity, dom_element); - } - } + for (var i = 0; i < status.mentions.length; i++) { + var mention = status.mentions[i]; + if(mention.post) { + _this.append(mention.post, mention.entity, dom_element); } } } - if(!entity) { - entity = node.status.entity + function getRemoteStatus(profile) { + var server = profile["https://tent.io/types/info/core/v0.1.0"].servers[0]; + Paths.getURL(URI(server + "/posts/" + id).toString(), "GET", callback, null, false); } - var url = HostApp.serverUrl("post") - .replace(/\{entity\}/, encodeURIComponent(entity)) - .replace(/\{post\}/, id) - + "?profiles=entity&max_refs=20"; + var profile = this.cache.profiles.getItem(entity); - APICalls.get(url, { callback: callback }); + if (entity == HostApp.stringForKey("entity")) { + + var url = URI(Paths.mkApiRootPath("/posts/" + id)); + Paths.getURL(url.toString(), "GET", callback, null); + + } else if(profile) { + + getRemoteStatus(profile); + + } else { + + Paths.findProfileURL(entity, function(profile_url) { + + if (profile_url) { + + var profile = this.cache.profiles.getItem(entity); + if (profile) { + + getRemoteStatus(profile); + + } else { + + Paths.getURL(profile_url, "GET", function(resp) { + + var profile = JSON.parse(resp.responseText) + this.cache.profiles.setItem(entity, profile); + getRemoteStatus(profile); + + }, null, false); // do not send auth-headers + } + } + }); + } } Conversation.prototype.appendMentioned = function(id, entity, node) { + var url = URI(Paths.mkApiRootPath("/posts")); + url.addSearch("mentioned_post", id); + url.addSearch("post_types", "https%3A%2F%2Ftent.io%2Ftypes%2Fpost%2Fstatus%2Fv0.1.0"); + var _this = this; var callback = function(resp) { - var statuses = JSON.parse(resp.responseText).mentions; - if (statuses) { - for (var i = 0; i < statuses.length; i++) { + var statuses = JSON.parse(resp.responseText); - var status = statuses[i]; + for (var i = 0; i < statuses.length; i++) { - // don't load if it is already there - var not_already_there = !document.getElementById("post-" + status.post + "-" + _this.action); - if(not_already_there && status.type.startsWith("https://tent.io/types/status/v0")) { - _this.append(status.post, status.entity, node, true); - } - } + var status = statuses[i]; + var dom_element = _this.getStatusDOMElement(status); + _this.body.appendChild(dom_element); + + _this.appendMentioned(status.id, status.entity, dom_element); } } - var url = HostApp.serverUrl("post") - .replace(/\{entity\}/, encodeURIComponent(entity)) - .replace(/\{post\}/, id); - - APICalls.get(url, { - callback: callback, - accept: "application/vnd.tent.post-mentions.v0+json" - }); + Paths.getURL(url.toString(), "GET", callback); } - Conversation.prototype.makeTree = function() { - var root_ul = document.createElement("ol"); - root_ul.id = "conversation-tree"; - var root_li = this.body.firstChild; - root_ul.appendChild(root_li); + // /posts?limit=10&mentioned_post=gnqqyt&post_types=https%3A%2F%2Ftent.io%2Ftypes%2Fpost%2Fstatus%2Fv0.1.0,https%3A%2F%2Ftent.io%2Ftypes%2Fpost%2Frepost%2Fv0.1.0 HTTP/1.1" 200 - 0.0582 - function addChildren(node) { - var ul = document.createElement("ol"); - node.appendChild(ul); - var children = node.cNode.children; - for (var i = 0; i < children.length; i++) { - var child = children[i].dom_node; - ul.appendChild(child); - addChildren(child); - }; - } - addChildren(root_li); - - this.body.parentNode.replaceChild(root_ul, this.body); - this.body = root_ul; - - var lis = this.body.querySelectorAll("li"); - for (var i = 0; i < lis.length; i++) { - lis[i].className += " " + (i % 2 == 0 ? "odd" : "even"); - }; - }; return Conversation; diff --git a/WebKit/scripts/controller/Mentions.js b/WebKit/scripts/controller/Mentions.js index 8140ba9..b60de05 100644 --- a/WebKit/scripts/controller/Mentions.js +++ b/WebKit/scripts/controller/Mentions.js @@ -1,205 +1,113 @@ define([ - "helper/HostApp", - "controller/Timeline", - "lib/URI", - "helper/APICalls", - "helper/Core" + "helper/HostApp", + "controller/Timeline", + "lib/URI", + "helper/Paths", + "helper/Core" ], -function(HostApp, Timeline, URI, APICalls, Core) { +function(HostApp, Timeline, URI, Paths, Core) { - function Mentions() { + function Mentions() { - this.is_not_init = false; - this.unread_mentions = 0; + this.is_not_init = false; + this.unread_mentions = 0; - Timeline.call(this); + Timeline.call(this); - this.action = "mentions"; - this.container.className = this.action; - - this.hide(); - } + this.action = "mentions"; + this.body.className = this.action; + + this.hide(); + } - Mentions.prototype = Object.create(Timeline.prototype); + Mentions.prototype = Object.create(Timeline.prototype); - Mentions.prototype.show = function() { - Core.prototype.show.call(this, this.container); - } + Mentions.prototype.show = function() { + Core.prototype.show.call(this, this.body); + } - Mentions.prototype.hide = function() { - Core.prototype.hide.call(this, this.container); - } + Mentions.prototype.hide = function() { + Core.prototype.hide.call(this, this.body); + } - Mentions.prototype.newStatus = function(statuses, append) { + Mentions.prototype.newStatus = function(statuses) { - Timeline.prototype.newStatus.call(this, statuses, append); + Timeline.prototype.newStatus.call(this, statuses); - if(this.is_not_init) { - for (var i = 0; i < statuses.posts.length; i++) { - - var status = statuses.posts[i]; - var name = bungloo.cache.profiles[status.entity] ? bungloo.cache.profiles[status.entity].name : status.entity + if(this.is_not_init) { - if(!append && status.type.startsWith("https://tent.io/types/status/v0#")) { - HostApp.notificateUserAboutMention(status.content.text, name, status.id, status.entity); - } - } - } + this.unread_mentions += statuses.length; + HostApp.unreadMentions(this.unread_mentions); - this.is_not_init = true; - } + for (var i = 0; i < statuses.length; i++) { + var status = statuses[i]; - Mentions.prototype.getNewData = function(add_to_search, append, query) { + var name; + var profile = this.cache.profiles.getItem(status.entity); + if(profile) { + name = profile["https://tent.io/types/info/basic/v0.1.0"].name; + } - add_to_search = add_to_search || {}; + HostApp.notificateUserAboutMention(status.content.text, name || status.entity, status.id, status.entity); + }; + } - if (!add_to_search["mentions"]) { - add_to_search["mentions"] = HostApp.stringForKey("entity"); - } + this.is_not_init = true; + } - Timeline.prototype.getNewData.call(this, add_to_search, append, query); + Mentions.prototype.getNewData = function(add_to_search) { - this.getLatestMentionRead(); - } + add_to_search = add_to_search || {}; - Mentions.prototype.mentionRead = function(id, entity) { - if (this.unread_mentions > 0) { - this.unread_mentions--; - HostApp.unreadMentions(this.unread_mentions); - } - } + if (!add_to_search["mentioned_entity"]) { + add_to_search["mentioned_entity"] = HostApp.stringForKey("entity"); + } - Mentions.prototype.setAllMentionsRead = function() { - this.unread_mentions = 0; - HostApp.unreadMentions(this.unread_mentions); - this.updateLatestMentionRead(); - } + Timeline.prototype.getNewData.call(this, add_to_search); + } - Mentions.prototype.updateLatestMentionRead = function() { + Mentions.prototype.mentionRead = function(id, entity) { + if (this.unread_mentions > 0) { + this.unread_mentions--; + HostApp.unreadMentions(this.unread_mentions); + } + } - var cursor_url = HostApp.serverUrl("posts_feed") + "?types=" + "https://tent.io/types/cursor/v0"; + Mentions.prototype.setAllMentionsRead = function() { + this.unread_mentions = 0; + HostApp.unreadMentions(this.unread_mentions); + this.updateLatestMentionRead(); + } - // find the first real post - for (var i = 0; i < this.body.childNodes.length; i++) { + Mentions.prototype.updateLatestMentionRead = function() { + var status = this.body.firstChild.status; - var status = this.body.childNodes[i].status; + if (status && status.type == "https://tent.io/types/post/status/v0.1.0") { - if (!status.__repost) { - if (status && status.type.startsWith("https://tent.io/types/status/v0#")) { + var url = URI(Paths.mkApiRootPath("/profile/" + encodeURIComponent("https://tent.io/types/info/cursor/v0.1.0"))); + var body = { + "https://tent.io/types/info/cursor/v0.1.0": { + "mentions": { + "https://tent.io/types/post/status/v0.1.0": { + "post_id": status.id, + "post_entity": status.entity + } + } + } + } - // First find out if there is such a cursor or if we need to create it first - APICalls.get(cursor_url, { callback: function(resp) { + var callback = function(resp) { + //debug(resp) + } - var posts = JSON.parse(resp.responseText).posts; - var mentions_post = null; - - for (var i = 0; i < posts.length; i++) { - var post = posts[i]; - - if(post.type == "https://tent.io/types/cursor/v0#https://tent.io/rels/status-mentions") { - - mentions_post = post; - - } - }; - - // Now prepare the cursor - - - var data = { - type: "https://tent.io/types/cursor/v0#https://tent.io/rels/status-mentions", - content: {}, - permissions: { - public: false, - }, - refs: [ - { - "post": status.id, - "type": status.type, - "entity": status.entity - } - ] - }; - - // update version if the post exists - if(mentions_post) { - data.version = { - parents: [ - { - version: mentions_post.version.id - } - ] - } - } - - var options = { - content_type: data.type, - accept: 'application/vnd.tent.post.v0+json; type="https://tent.io/types/cursor/v0#https://tent.io/rels/status-mentions"', - callback: function(resp) { - - }}; - - // either update or create the cursor - if(mentions_post) { - var url = HostApp.serverUrl("post") - .replace(/\{entity\}/, encodeURIComponent(HostApp.stringForKey("entity"))) - .replace(/\{post\}/, mentions_post.id) - APICalls.put(url, JSON.stringify(data), options); - } else { - var url = HostApp.serverUrl("posts_feed"); - APICalls.post(url, JSON.stringify(data), options); - } - - }}); - } - - break; - } - } - - } + Paths.getURL(url.toString(), "PUT", callback, JSON.stringify(body)); + } + } - Mentions.prototype.getLatestMentionRead = function() { - - var cursor_url = HostApp.serverUrl("posts_feed") + "?types=" + "https://tent.io/types/cursor/v0"; - - APICalls.get(cursor_url, { callback: function(resp) { - - var posts = JSON.parse(resp.responseText).posts; - - for (var i = 0; i < posts.length; i++) { - var post = posts[i]; - - if(post.type == "https://tent.io/types/cursor/v0#https://tent.io/rels/status-mentions") { - - var since = post.version.received_at; - var post_id = post.refs[0].post; - var post_types = [ - "https://tent.io/types/status/v0#reply", - "https://tent.io/types/status/v0#" - ]; - - var uri = URI(HostApp.serverUrl("posts_feed")); - uri.addSearch("types", post_types.join(",")); - uri.addSearch("since", since); - uri.addSearch("mentions", HostApp.stringForKey("entity")); - - APICalls.head(uri.toString(), { callback: function(resp) { - - this.unread_mentions = APICalls.getCount(resp); - HostApp.unreadMentions(this.unread_mentions); - - }}); - } - }; - - }}); - } - - return Mentions; + return Mentions; }); \ No newline at end of file diff --git a/WebKit/scripts/controller/NewPost.js b/WebKit/scripts/controller/NewPost.js deleted file mode 100644 index e489041..0000000 --- a/WebKit/scripts/controller/NewPost.js +++ /dev/null @@ -1,396 +0,0 @@ -define([ - "helper/APICalls", - "helper/HostApp" -], - -function(APICalls, HostApp) { - - function NewPost() { - - this.profiles = JSON.parse(controller.getCachedProfiles()); - for (var key in this.profiles) { - var item = this.profiles[key]; - if(!item.entity) item.entity = key; - if(!item.name) item.name = key; - } - - this.mentions = []; - document.body.className = "new_post"; - this.is_private = false; - - // Textarea - - this.container = $("
"); - this.textarea = this.container.find("textarea"); - this.highlighter = this.container.find("div"); - - $(document.body).append(this.container); - - var _this = this; - - this.textarea.keyup(function(e) { _this.keyup(e) }); - this.textarea.keydown(function(e) { _this.keydown(e) }); - - this.suggestions = $("
    "); - - $(document.body).append(this.suggestions); - - // Status bar - this.counter = $("256"); - var buttons = $( - "

    " + - //"" + - " " + - "" + - "

    "); - - this.buttons = { - images: buttons.find("#images"), - is_private: buttons.find("#private"), - send: buttons.find("#send") - } - - //this.buttons.images.bind("click", this.addImage.bind(this)); - - this.buttons.is_private.bind("click", function(e) { _this.toggleIsPrivate(e) ; } ); - this.buttons.send.bind("click", function (e) { _this.send(e); }); - - this.container.find("#status_bar").append(this.counter); - this.container.find("#status_bar").append(buttons); - - this.textarea.focus(); - this.setIsPrivate(false); - } - - NewPost.prototype.setStatus = function(status_string) { - if (status_string && status_string.length > 0) { - this.status = JSON.parse(status_string); - this.setIsPrivate(this.status.permissions && !this.status.permissions.public); - this.setMentions(this.status); - } else { - this.status = null; - } - - // FIXME set string, private, mentions, etc. - }; - - NewPost.prototype.setString = function(string) { - this.textarea.val(string); - } - - NewPost.prototype.setMentions = function(status) { - - var mentions = [this.profiles[status.entity]]; - var text = this.profiles[status.entity].name + " "; - var start = text.length; - - if(status.mentions && status.mentions.length > 0) { - - var mentions_text = "" - for (var i = 0; i < status.mentions.length; i++) { - - var entity = status.mentions[i].entity; - - // Sometimes there are mentions without entity, don't know why - if(entity && entity != HostApp.stringForKey("entity")) { - // fix broken profiles - var profile = this.profiles[entity]; - if(!profile) { - profile = {}; - this.profiles[entity] = profile; - } - if(!profile.entity) profile.entity = entity; - if(!profile.name) profile.name = entity; - - // add profile to mentions and textarea - mentions.push(profile); - mentions_text += profile.name; - - // add space after mention - if(i < status.mentions.length) { - mentions_text += " "; - } - } - } - if (mentions_text.length > 0) { - text += "\n\n/cc " + mentions_text; - }; - - } - - this.mentions = mentions; - this.textarea.val(text); - this.parseText(text); - - // Select other mentions so user can start writing and removing them - var end = text.length; - this.textarea.get(0).setSelectionRange(start, end); - } - - NewPost.prototype.setIsPrivate = function(is_private) { - this.is_private = is_private; - if (this.is_private) { - this.buttons.is_private.find("img").attr("src", "img/private.png"); - } else { - this.buttons.is_private.find("img").attr("src", "img/public.png"); - } - } - - NewPost.prototype.toggleIsPrivate = function() { - this.setIsPrivate(!this.is_private); - } - - NewPost.prototype.keyup = function(e) { - if(!e) return; - - var key = e.which; - if(key != 38 && key != 40 && key != 13) { - - this.applyText($(this.textarea).val()); - - } else { - - var lis = this.suggestions.find("li"); - - if (lis.length > 0) { - e.preventDefault(); - var active = this.suggestions.find(".active"); - if(key == 38) { // up - var prev = active.prev(); - if(active.lentgh == 0) { - lis.last().addClass("active"); - } else if(prev) { - active.removeClass("active"); - prev.addClass("active"); - } - } else if(key == 40) { // down - var next = active.next(); - if(active.length == 0) { - lis.first().addClass("active"); - } else if(next) { - active.removeClass("active"); - next.addClass("active"); - } - } else if(key == 13) { // enter - if(active.length > 0) { - this.replaceWithName(this.textarea.val(), this.suggestions.find("li.active").get(0).item); - } - } - } - } - } - - NewPost.prototype.keydown = function(e) { - var key = e.which; - var lis = this.suggestions.find("li"); - if(lis.length > 0 && (key == 38 || key == 40 || key == 13)) { - e.preventDefault(); - } - } - - NewPost.prototype.replaceAll = function(txt, replace, with_this) { - return txt.replace(new RegExp(replace, 'g'), with_this); - } - - NewPost.prototype.replaceWithName = function(txt, with_item) { - var words = txt.match(/(^|\s)\^([^\s]+)/); - var replace = words[2]; - - var original = txt.replace("^" + replace, with_item.name + " "); - this.textarea.val(original); - - this.mentions.push(with_item); - - this.applyText(original); - } - - NewPost.prototype.applyText = function (text) { - var words = text.match(/(^|\s)\^([^\s]+)/); - this.suggestions.html(""); - - if(words) { - var name = words[2]; - for (var key in this.profiles) { - var item = this.profiles[key]; - if((item.name.toLowerCase().indexOf(name.toLowerCase()) != -1) || item.entity.toLowerCase().indexOf(name.toLowerCase()) != -1) { - var li = $("
  • " + item.name + "
  • ") - li.get(0).item = item; - this.suggestions.append(li); - } - } - this.suggestions.find("li:first-child").addClass("active"); - } - - this.parseText(text); - } - - NewPost.prototype.parseText = function(text) { - // parse the text: - // replace all the line braks by
    , and all the double spaces by the html version   - text = this.replaceAll(text,'\n','
    '); - //text = this.replaceAll(text,' ','  '); - - // replace the words by a highlighted version of the words - - var remove = []; - - for (var i=0;i' + name + ''); - } else { - remove.push(this.mentions[i]); - } - } - - for (var i = 0; i < remove.length; i++) { - this.mentions.splice(this.mentions.indexOf(remove[i]), 1); - } - - // re-inject the processed text into the div - this.highlighter.html(text); - - var count = 256 - (this.textarea.val().length + (this.mentions.length * 6)); - this.counter.html(count); - } - - NewPost.prototype.send = function() { - - var count = 256 - (this.textarea.val().length + (this.mentions.length * 6)); - if(count >= 0 && count <= 256) { - this.sendNewMessage(); - return true; - } else { - return false; - } - } - - NewPost.prototype.sendNewMessage = function() { - - var content = this.textarea.val(); - - var data = { - type: "https://tent.io/types/status/v0#", - content: { - text: content - }, - permissions: { - public: !this.is_private - } - }; - - var mentions = []; - for (var i = 0; i < this.mentions.length; i++) { - var mention = this.mentions[i]; - if(this.status && this.status.entity == mention.entity) { - mentions.push({ - entity: this.status.entity, - post: this.status.id, - type: this.status.type - }); - } else { - mentions.push({ - entity: mention.entity - }); - } - } - - data.mentions = mentions; - - // Make tent flavored markdown mentions - for (var i = 0; i < this.mentions.length; i++) { - var mention = this.mentions[i]; - data.content.text = this.replaceAll(data.content.text, mention.name, "^[" + mention.name + "](" + i + ")") - } - - APICalls.post(HostApp.serverUrl("new_post"), JSON.stringify(data), { - content_type: data.type, - accept: 'application/vnd.tent.post.v0+json; type="https://tent.io/types/status/v0#"', - callback: function(resp) { - if (resp.status >= 200 < 300) { - new_post_window.closeWindow(); - controller.getNewData(); - } else { - new_post_window.beep(); - } - } - }); - } -/* - NewPost.prototype.sendNewMessageWithImage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, is_private, callback) { - - var url = URI(APICalls.mkApiRootPath("/posts")); - - var data = { - "type": "https://tent.io/types/post/photo/v0.1.0", - "published_at": parseInt(new Date().getTime() / 1000, 10), - "permissions": { - "public": !is_private - }, - "content": { - "caption": content, - }, - }; - - if (location) { - data["content"]["location"] = { "type": "Point", "coordinates": location } - } - - var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity); - if (mentions.length > 0) { - data["mentions"] = mentions; - if (is_private) { - var entities = {}; - for (var i = 0; i < mentions.length; i++) { - var entity = mentions[i]["entity"] - entities[entity] = true; - }; - - data["permissions"]["entities"] = entities; - } - } - - var data_string = JSON.stringify(data); - - var boundary = "TentAttachment----------TentAttachment"; - var post = "--" + boundary + "\r\n"; - - post += 'Content-Disposition: form-data; name="post"; filename="post.json"\r\n'; - post += 'Content-Length: ' + data_string.length + '\r\n'; - post += 'Content-Type: application/vnd.tent.v0+json\r\n'; - post += 'Content-Transfer-Encoding: binary\r\n\r\n'; - post += data_string; - - post += "\r\n--" + boundary + "\r\n"; - - var blob_string = image_data_uri.split(',')[1]; - var mime_type = image_data_uri.split(',')[0].split(':')[1].split(';')[0]; - var ext = "png"; - if (mime_type == "image/jpeg") { - ext = "jpeg"; - } else if (mime_type == "image/gif") { - ext = "gif"; - } - - - post += 'Content-Disposition: form-data; name="photos[0]"; filename="photo.' + ext + '"\r\n'; - post += 'Content-Length: ' + blob_string.length + "\r\n"; - post += 'Content-Type: ' + mime_type + "\r\n"; - post += 'Content-Transfer-Encoding: base64\r\n\r\n'; - post += blob_string; - post += "\r\n--" + boundary + "--\r\n"; - - var newCallback = function(resp) { - if (resp.status == 403) { - var err = JSON.parse(resp.responseText); - HostApp.alertTitleWithMessage(resp.statusText, err.error); - } - callback(resp); - } - - APICalls.postMultipart(url.toString(), newCallback, post, boundary); - } -*/ - - return NewPost; -}) \ No newline at end of file diff --git a/WebKit/scripts/controller/Oauth.js b/WebKit/scripts/controller/Oauth.js index 6ce5019..e4c04cc 100644 --- a/WebKit/scripts/controller/Oauth.js +++ b/WebKit/scripts/controller/Oauth.js @@ -1,45 +1,30 @@ define([ "helper/HostApp", - "helper/APICalls", + "helper/Paths", "helper/Hmac" ], -function(HostApp, APICalls, Hmac) { +function(HostApp, Paths, Hmac) { function Oauth() { this.app_info = { - "type": "https://tent.io/types/app/v0#", - "content": { - "name": "Bungloo on " + HostApp.osType(), - "url": "http://jabs.nu/bungloo/", - "description": "A desktop Tent client.", - "redirect_uri": "bungloo://oauthtoken", - "types": { - "read": [ - "https://tent.io/types/meta/v0", - "https://tent.io/types/relationship/v0", - "https://tent.io/types/subscription/v0", - "https://tent.io/types/delete/v0", - "https://tent.io/types/status/v0", - "https://tent.io/types/repost/v0", - "https://tent.io/types/photo/v0", - "https://tent.io/types/cursor/v0", - "https://tent.io/types/basic-profile/v0" - ], - "write": [ - "https://tent.io/types/relationship/v0", - "https://tent.io/types/subscription/v0", - "https://tent.io/types/delete/v0", - "https://tent.io/types/status/v0", - "https://tent.io/types/repost/v0", - "https://tent.io/types/photo/v0", - "https://tent.io/types/cursor/v0" - ] - }, - "scopes": ["permissions"] - }, - "permissions": { - "public": false + "id": null, + "name": "Bungloo on " + HostApp.osType(), + "description": "A small TentStatus client.", + "url": "http://jabs.nu/bungloo/", + "icon": "http://jabs.nu/bungloo/icon.png", + "redirect_uris": [ + "bungloo://oauthtoken" + ], + "scopes": { + "read_posts": "Uses posts to show them in a list", + "write_posts": "Posts on users behalf", + "read_profile": "Displays your own profile", + "write_profile": "Updating profile and mentions pointer", + "read_followers": "Display a list of people who follow you", + "write_followers": "Be able to block people who follow you", + "read_followings": "Display following list and their older posts in conversations", + "write_followings": "Follow ne entities" } }; this.register_data = null; @@ -48,121 +33,110 @@ function(HostApp, APICalls, Hmac) { } Oauth.prototype.isAuthenticated = function() { - return !!HostApp.stringForKey("user_access_token"); + return HostApp.stringForKey("user_access_token") != null; } Oauth.prototype.authenticate = function() { var entity = HostApp.stringForKey("entity"); - if (entity && entity.startsWith("http")) { - if((entity.startsWith("http://") || entity.startsWith("https://"))) { - this.entity = entity; - this.requestProfileURL(this.entity); - } else { - this.entity = "https://" + entity; - HostApp.setStringForKey(this.entity, "entity"); - this.requestProfileURL(this.entity); - } + if (entity && (entity.startsWith("http://") || entity.startsWith("https://"))) { + this.entity = entity; + this.requestProfileURL(this.entity); } else { HostApp.authentificationDidNotSucceed("The entity should start with https:// or http://"); } } + Oauth.prototype.apiRoot = function() { + return this.profile["https://tent.io/types/info/core/v0.1.0"]["servers"][0]; + } + Oauth.prototype.requestProfileURL = function (entity) { - var _this = this; - APICalls.findProfileURL(entity, + var those = this; + Paths.findProfileURL(entity, function(profile_url) { if (profile_url && (profile_url.startsWith("http://") || profile_url.startsWith("https://"))) { - _this.register(profile_url); + those.register(profile_url); } else { HostApp.authentificationDidNotSucceed("Could not find profile for: " + entity); } }, function(errorMessage) { // error callback - HostApp.authentificationDidNotSucceed(errorMessage); HostApp.authentificationDidNotSucceed("Could not find profile for: " + entity); } ); } Oauth.prototype.register = function (url) { - var _this = this; + var those = this; - APICalls.get(url, { - no_auth: true, - callback: function(resp) { + Paths.getURL(url, "GET", function(resp) { - _this.profile = JSON.parse(resp.responseText).post; - _this.entity = _this.profile.content.entity; - HostApp.setStringForKey(_this.entity, "entity") - HostApp.setServerUrls(_this.profile.content.servers[0].urls); - APICalls.post(HostApp.serverUrl("new_post"), JSON.stringify(_this.app_info), { - content_type: "https://tent.io/types/app/v0#", - no_auth: true, - callback: function(resp) { - var app_id = JSON.parse(resp.responseText).post.id; - var header_string = resp.getAllResponseHeaders(); - var regexp = /https:\/\/tent.io\/rels\/credentials/i - var url = APICalls.parseHeaderForLink(header_string, regexp); + those.profile = JSON.parse(resp.responseText); + those.entity = those.profile["https://tent.io/types/info/core/v0.1.0"].entity; + HostApp.setStringForKey(those.entity, "entity") + HostApp.setStringForKey(those.apiRoot(), "api_root"); - APICalls.get(url, { - content_type: "https://tent.io/types/app/v0#", - no_auth: true, - callback: function(resp) { - var data = JSON.parse(resp.responseText); - _this.authRequest(data.post, app_id); - } - }); - }}); - - }}); + var callback = function(resp) { + var data = JSON.parse(resp.responseText); + those.authRequest(data); + } + Paths.getURL(Paths.mkApiRootPath("/apps"), "POST", callback, JSON.stringify(those.app_info), false); + }, null, false); } - Oauth.prototype.authRequest = function(credentials, app_id) { - - HostApp.setStringForKey(app_id, "app_id"); - HostApp.setStringForKey(credentials.id, "app_hawk_id"); - HostApp.setStringForKey(credentials.content.hawk_key, "app_hawk_key"); - HostApp.setStringForKey(credentials.content.hawk_algorithm, "app_hawk_algorithm"); - + Oauth.prototype.authRequest = function(register_data) { + // id + // mac_key_id + // mac_key + // mac_algorithm + this.register_data = register_data; + + // Needed for later App Registration Modification + HostApp.setStringForKey(register_data["mac_key"], "app_mac_key"); + HostApp.setStringForKey(register_data["mac_key_id"], "app_mac_key_id"); + HostApp.setStringForKey(register_data["id"], "app_id"); + HostApp.setStringForKey(register_data["mac_algorithm"], "app_mac_algorithm"); + this.state = Hmac.makeid(19); - var url = HostApp.serverUrl("oauth_auth") + "?client_id=" + app_id + "&state=" + this.state; - HostApp.openAuthorizationURL(url); + var auth = "/oauth/authorize?client_id=" + register_data["id"] + + "&redirect_uri=" + this.app_info["redirect_uris"][0] + + "&scope=" + Object.keys(this.app_info["scopes"]).join(",") + + "&state=" + this.state + + "&tent_post_types=all" + + "&tent_profile_info_types=all"; + + HostApp.openAuthorizationURL(this.apiRoot() + auth); } Oauth.prototype.requestAccessToken = function(responseBody) { // /oauthtoken?code=51d0115b04d1ed94001dde751c5b360f&state=aQfH1VEohYsQr86qqyv - // https://app.example.com/oauth?code=K4m2J2bGI9rcICBqmUCYuQ&state=d173d2bb868a - var urlVars = APICalls.getUrlVars(responseBody); + var urlVars = Paths.getUrlVars(responseBody); if(this.state && this.state != "" && urlVars["state"] == this.state) { - var url = HostApp.serverUrl("oauth_token"); + var url = Paths.mkApiRootPath("/apps/") + this.register_data["id"] + "/authorizations"; var requestBody = JSON.stringify({ 'code' : urlVars["code"], - 'token_type': "https://tent.io/oauth/hawk-token" + 'token_type' : "mac" }); var those = this; - var auth_header = Hmac.makeHawkAuthHeader( + var http_method = "POST"; + var callback = function(resp) { + those.requestAccessTokenTicketFinished(resp.responseText); + }; + + var auth_header = Hmac.makeAuthHeader( url, - "POST", - HostApp.stringForKey("app_hawk_id"), - HostApp.stringForKey("app_hawk_key") + http_method, + HostApp.stringForKey("app_mac_key"), + HostApp.stringForKey("app_mac_key_id") ); - APICalls.post(url, requestBody, { - content_type: "application/json", - auth_header: auth_header, - callback: function(resp) { - debug(url) - debug(requestBody) - debug(auth_header) - debug(resp.responseText) - those.requestAccessTokenTicketFinished(resp.responseText); - }}); + Paths.getURL(url, http_method, callback, requestBody, auth_header); } else { console.error("State is not the same: {" + this.state + "} vs {" + urlVars["state"] + "}") @@ -176,16 +150,16 @@ function(HostApp, APICalls, Hmac) { var access = JSON.parse(responseBody); HostApp.setStringForKey(access["access_token"], "user_access_token"); - HostApp.setSecret(access["hawk_key"]); - HostApp.setStringForKey(access["hawk_algorithm"], "user_hawk_algorithm"); + HostApp.setSecret(access["mac_key"]); + HostApp.setStringForKey(access["mac_algorithm"], "user_mac_algorithm"); HostApp.setStringForKey(access["token_type"], "user_token_type"); HostApp.loggedIn(); } - Oauth.prototype.logout = function() { // FIXME + Oauth.prototype.logout = function() { - var url = APICalls.mkApiRootPath("/apps/" + HostApp.stringForKey("app_id")); + var url = Paths.mkApiRootPath("/apps/" + HostApp.stringForKey("app_id")); var http_method = "DELETE"; var auth_header = Hmac.makeAuthHeader( url, @@ -194,7 +168,7 @@ function(HostApp, APICalls, Hmac) { HostApp.stringForKey("app_mac_key_id") ); - APICalls.http_call(url, http_method, function(resp) { + Paths.getURL(url, http_method, function(resp) { HostApp.setStringForKey(null, "app_mac_key"); HostApp.setStringForKey(null, "app_mac_key_id"); HostApp.setStringForKey(null, "app_id"); diff --git a/WebKit/scripts/controller/Profile.js b/WebKit/scripts/controller/Profile.js index 7f922ba..b3913d3 100644 --- a/WebKit/scripts/controller/Profile.js +++ b/WebKit/scripts/controller/Profile.js @@ -1,665 +1,641 @@ define([ - "helper/HostApp", - "helper/Core", - "helper/APICalls", - "lib/URI", - "controller/Timeline" + "helper/HostApp", + "helper/Core", + "helper/Paths", + "lib/URI" ], -function(HostApp, Core, APICalls, URI, Timeline) { +function(HostApp, Core, Paths, URI) { - function Profile() { - - Timeline.call(this); - clearTimeout(this.reloadIntervall); // FIXME: reload for new data instead - - this.action = "profile"; + function Profile() { - this.container = document.createElement("div"); - this.container.className = this.action; - document.getElementById("content").appendChild(this.container); + Core.call(this); - this.initProfileTemplate(); - this.hide(); - } + this.action = "profile"; - Profile.prototype = Object.create(Timeline.prototype); - + this.container = document.createElement("div"); + document.getElementById("content").appendChild(this.container); - Profile.prototype.show = function() { - Core.prototype.show.call(this, this.container); - } - - Profile.prototype.hide = function() { - Core.prototype.hide.call(this, this.container); - } - - Profile.prototype.logout = function() { - this.container = ""; - } - - Profile.prototype.showList = function(list) { - $(this.body).hide(); - $(this.followingsBody).hide(); - $(this.followersBody).hide(); - $(list).show(); - } - - Profile.prototype.showEntity = function(a, i) { - var entity = $(a).closest("li").get(0).status.mentions[i].entity; - this.showProfileForEntity(entity); - bungloo.sidebar.onEntityProfile(); - }; - - Profile.prototype.showProfileForEntity = function(entity) { - - if (!entity) { - entity = HostApp.stringForKey("entity"); - } - - this.clear(); - this.entity = entity; - this.following = null; - this.following_id = null; - this.profile_template.entity.innerHTML = this.entity; - this.profile_template.entity.href = this.entity; - - this.getProfile(); - this.getFollowing(); - this.getStatuses(); - } - - Profile.prototype.initProfileTemplate = function() { - - var _this = this; - - var header = document.createElement("header"); - header.className = "profile"; + this.initProfileTemplate(); + this.hide(); - this.container.appendChild(header); + var _this = this; + setTimeout(function() { _this.showProfileForEntity() }, 5000); // Load users profile on start + } - this.profile_template = { - avatar: document.createElement("img"), - name: document.createElement("h1"), - entity: document.createElement("a"), - bio: document.createElement("p"), - relationships: document.createElement("td"), - posts: document.createElement("a"), - following: document.createElement("a"), - followed: document.createElement("a"), - birthdate: document.createElement("td"), - location: document.createElement("td"), - gender: document.createElement("td"), - url: document.createElement("a"), - following_button: document.createElement("button"), - mention_button: document.createElement("button") - }; + Profile.prototype = Object.create(Core.prototype); + - header.appendChild(this.profile_template.avatar); - this.profile_template.avatar.src = "img/default-avatar.png"; - - var div = document.createElement("div"); - header.appendChild(div); - - this.profile_template.following_button.onclick = function(e) { - _this.toggleFollow() - } - div.appendChild(this.profile_template.following_button); - - this.profile_template.mention_button.onclick = function() { - HostApp.openNewMessageWidow({entity:_this.entity}); - } - div.appendChild(this.profile_template.mention_button); - this.profile_template.mention_button.innerHTML = "Mention"; - - div.appendChild(this.profile_template.name); - - var p = document.createElement("p"); - p.appendChild(this.profile_template.entity); - div.appendChild(p); - - div.appendChild(this.profile_template.bio); - - var table = document.createElement("table"); - div.appendChild(table); - - function mkLi(name, template) { - var tr = document.createElement("tr"); - var th = document.createElement("th"); - tr.style.display = "none"; - th.innerText = name + ": "; - tr.appendChild(th); - tr.appendChild(template); - table.appendChild(tr); - } - - mkLi("Birth date", this.profile_template.birthdate); - mkLi("Location", this.profile_template.location); - mkLi("Gender", this.profile_template.gender); - - var td = document.createElement("td"); - td.appendChild(this.profile_template.url); - mkLi("Homepage", td); - - mkLi("Relationships", this.profile_template.relationships); - - td = document.createElement("td"); - td.appendChild(this.profile_template.posts); - this.profile_template.posts.href = "#"; - this.profile_template.posts.onclick = function() { _this.showPosts(); return false; }; - mkLi("Posts", td); - - td = document.createElement("td"); - td.appendChild(this.profile_template.following); - this.profile_template.following.href = "#"; - this.profile_template.following.onclick = function() { _this.showFollowings(); return false; }; - mkLi("Following", td); - - td = document.createElement("td"); - td.appendChild(this.profile_template.followed); - this.profile_template.followed.href = "#"; - this.profile_template.followed.onclick = function() { _this.showFollowers(); return false; }; - mkLi("Followed by", td); - - - this.body = document.createElement("ol"); - this.body.className = this.action; - this.container.appendChild(this.body); - - this.followingsBody = document.createElement("ol"); - this.followingsBody.className = this.action + " followings"; - this.container.appendChild(this.followingsBody); - - this.followersBody = document.createElement("ol"); - this.followersBody.className = this.action + " folloewds"; - this.container.appendChild(this.followersBody); - - } - - Profile.prototype.clear = function() { - - this.server = null; - this.before = {id: null, entity: null, loading: false}; - - - this.profile_template.avatar.src = "img/default-avatar.png"; - - this.relationships = { - following_you: false, - followed_by_you: false, - it_is_you: false - } - - this.profile_template.name.innerText = ""; - this.profile_template.entity.innerText = ""; - this.profile_template.bio.innerText = ""; - this.profile_template.relationships.innerText = ""; - this.profile_template.posts.innerText = ""; - this.profile_template.following.innerText = ""; - this.profile_template.followed.innerText = ""; - this.profile_template.birthdate.innerText = ""; - this.profile_template.location.innerText = ""; - this.profile_template.gender.innerText = ""; - this.profile_template.url.innerText = ""; - this.profile_template.url.href = ""; - - this.profile_template.posts.parentNode.parentNode.style.display = "none"; - this.profile_template.following.parentNode.parentNode.style.display = "none"; - this.profile_template.followed.parentNode.parentNode.style.display = "none"; - this.profile_template.birthdate.parentNode.style.display = "none"; - this.profile_template.location.parentNode.style.display = "none"; - this.profile_template.gender.parentNode.style.display = "none"; - this.profile_template.url.parentNode.parentNode.style.display = "none"; - - this.profile_template.following_button.style.display = ""; - this.setFollowingButton(false); - - this.body.innerHTML = ""; - this.followingsBody.innerHTML = ""; - this.followersBody.innerHTML = ""; - - this.showList(this.body); - }; - - Profile.prototype.getProfile = function() { - - var _this = this; - - if (HostApp.stringForKey("entity") == this.entity) { - this.relationships.it_is_you = true; - this.profile_template.following_button.style.display = "none"; - } - - var url = HostApp.serverUrl("posts_feed") + "?types=" + encodeURIComponent("https://tent.io/types/meta/v0") + "&entities=" + encodeURIComponent(this.entity); - APICalls.get(url, { - callback: function(resp) { - var profile = JSON.parse(resp.responseText); - _this.showProfile(profile); - _this.profile = profile; - }}); - } - - Profile.prototype.getFollowing = function() { - if(this.entity != HostApp.stringForKey("entity")) { - - var url = HostApp.serverUrl("posts_feed") + "?mentions=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/subscription/v0#https://tent.io/types/status/v0"); - var _this = this; - - APICalls.get(url, {callback: function(resp) { - - var json = JSON.parse(resp.responseText); - var count = json.posts.length; - - if (count > 0) { - _this.setFollowingButton(true); - _this.following_id = json.posts[0].id; - } else { - _this.setFollowingButton(false); - delete _this.following_id; - } - - }}); - - } else { - - this.setFollowingButton(false); - this.following_id = null; - } - } - - Profile.prototype.showProfile = function(profiles) { - - if(profiles.posts.length < 1) return; - var profile = profiles.posts[0]; - bungloo.cache.profiles[profile.entity] = profile.content.profile; - - var basic = profile.content.profile; - - if (profile && basic) { - - // Find and apply avatar - if(profile.attachments) { - - var digest = null; - for (var i = 0; i < profile.attachments.length; i++) { - var attachment = profile.attachments[i]; - if(attachment.category == "avatar") { - digest = attachment.digest; - break; - } - } - - if(digest) { - var _this = this; - this.profile_template.avatar.onerror = function() { _this.profile_template.avatar.src = 'img/default-avatar.png' }; - var avatar_url = profile.content.servers[0].urls.attachment.replace(/\{entity\}/, encodeURIComponent(profile.entity)); - this.profile_template.avatar.src = avatar_url.replace(/\{digest\}/, digest); - } - } - - this.populate(this.profile_template.name, basic.name); - this.populate(this.profile_template.birthdate, basic.birthdate); - this.populate(this.profile_template.location, basic.location); - this.populate(this.profile_template.gender, basic.gender); - this.populate(this.profile_template.bio, basic.bio); - - if(basic.website) { - - var url = basic.website; - this.profile_template.url.innerText = url; - this.profile_template.url.parentNode.parentNode.style.display = ""; - - if (!url.startsWith("http")) { - url = "http://" + url; - } - - this.profile_template.url.href = url; - } - } - - if (profile) { - this.profile = profile; - - // FIXME - this.getMeta(this.profile); - this.getStatuses(); - } - } - - Profile.prototype.populate = function(t, v) { - if (v) { - t.innerText = v; - t.parentNode.style.display = ""; - t.parentNode.parentNode.style.display = ""; - } - } - - Profile.prototype.getMeta = function(profile) { - - // FIXME! - - var _this = this; -/* - var url = HostApp.serverUrl("posts_feed") + "?entities=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/subscription/v0#"); - APICalls.head(url, { - callback: function(resp) { - _this.populate(_this.profile_template.followed, APICalls.getCount(resp) + " "); - } - }); - - var url = HostApp.serverUrl("posts_feed") + "?entities=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/relationship/v0#following"); - APICalls.head(url, { - callback: function(resp) { - _this.populate(_this.profile_template.following, APICalls.getCount(resp) + " "); - } - }); - - var url = HostApp.serverUrl("posts_feed") + "?entities=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/status/v0#"); - APICalls.head(url, { - callback: function(resp) { - _this.populate(_this.profile_template.posts, APICalls.getCount(resp) + " "); - } - }); -*/ - - // is following you - // FIXME: should use HEAD - var url = HostApp.serverUrl("posts_feed") + "?entities=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/subscription/v0#https://tent.io/types/status/v0") + "&mentions=" + encodeURIComponent(HostApp.stringForKey("entity")); - APICalls.get(url, { - callback: function(resp) { - var json = JSON.parse(resp.responseText); - if (json.posts.length > 0) { - _this.relationships.following_you = true; - } else { - _this.relationships.following_you = false; - } - _this.setRelationships(); - } - }); - - // is followed by you - // FIXME: should use HEAD - var url = HostApp.serverUrl("posts_feed") + "?mentions=" + encodeURIComponent(this.entity) + "&types=" + encodeURIComponent("https://tent.io/types/subscription/v0#https://tent.io/types/status/v0"); - APICalls.get(url, { - callback: function(resp) { - var json = JSON.parse(resp.responseText); - if (json.posts.length > 0) { - _this.relationships.followed_by_you = true; - } else { - _this.relationships.followed_by_you = false; - } - _this.setRelationships(); - } - }); - - return; -/* - - - if (this.entity != HostApp.stringForKey("entity")) { - APICalls.http_call(URI(root_url + "/followers/" + encodeURIComponent(HostApp.stringForKey("entity"))).toString(), "GET", function(resp) { - if (resp.status == 200) { - _this.relationships.following_you = true; - } - _this.setRelationships(); - - }, null, false); - - APICalls.http_call(URI(APICalls.mkApiRootPath("/followings/" + encodeURIComponent(this.entity))), "GET", function(resp) { - if (resp.status == 200) { - _this.relationships.followed_by_you = true; - } - _this.setRelationships(); - }); - - } else { - this.setRelationships(); - } - - - var url = URI(root_url + "/posts/count"); - var post_types = [ - "https://tent.io/types/post/repost/v0.1.0", - "https://tent.io/types/post/status/v0.1.0", - "https://tent.io/types/post/photo/v0.1.0" - ]; - url.addSearch("post_types", post_types.join(",")); - - APICalls.http_call(url.toString(), "GET", function(resp) { - - _this.populate(_this.profile_template.posts, resp.responseText); - }, null, false);*/ - } - - Profile.prototype.setRelationships = function() { - var relation = "none"; - if (HostApp.stringForKey("entity") == this.entity) { - relation = "it's you"; - } else { - if (this.relationships.following_you && !this.relationships.followed_by_you) { - relation = "is following you"; - } else if (this.relationships.following_you && this.relationships.followed_by_you) { - relation = "you both follow each other"; - } else if (!this.relationships.following_you && this.relationships.followed_by_you) { - relation = "being followed by you"; - } - } - this.populate(this.profile_template.relationships, relation); - } - - - Profile.prototype.getStatuses = function() { - this.since_time = null; - Timeline.prototype.getNewData.call(this, {entities: this.entity}); - } - - Profile.prototype.setFollowingButton = function(following) { - - this.following = following; - - if (following) { - this.profile_template.following_button.className = "following"; - this.profile_template.following_button.innerText = "Unfollow"; - } else { - this.profile_template.following_button.className = ""; - this.profile_template.following_button.innerText = "Follow"; - } - } - - Profile.prototype.toggleFollow = function() { - - var _this = this; - - if (this.following_id) { - - this.setFollowingButton(false); - - var url = HostApp.serverUrl("post").replace(/\{entity\}/, encodeURIComponent(HostApp.stringForKey("entity"))).replace(/\{post\}/, this.following_id); - APICalls.delete(url, { callback: function(resp) { - if (resp.status >= 200 && resp.status < 300) { - _this.setFollowingButton(false); - delete _this.following_id; - } else { - _this.setFollowingButton(true); - } - _this.getMeta(); - }}); - - } else { - - this.setFollowingButton(true); - - var url = HostApp.serverUrl("new_post"); - - var data = { - content: { - type: "https://tent.io/types/status/v0" - }, - mentions: [{ - entity: this.entity - }], - type: "https://tent.io/types/subscription/v0#https://tent.io/types/status/v0" - }; - - APICalls.post(url, JSON.stringify(data), { - content_type: data.type, - callback: function(resp) { - if (resp.status >= 200 && resp.status < 300) { - _this.setFollowingButton(true); - var json = JSON.parse(resp.responseText); - _this.following_id = json.post.id; - } else { - _this.setFollowingButton(false); - } - _this.getMeta(); - } - }); - } - } - - Profile.prototype.showPosts = function() { - this.showList(this.body); - } - - Profile.prototype.showFollowings = function() { - - this.showList(this.followingsBody); - this.followingsBody.innerHTML = ""; - - var _this = this; - var callback = function(resp) { - var followings = JSON.parse(resp.responseText); - for (var i = 0; i < followings.length; i++) { - var li = _this.getDOMSmallProfile(followings[i]); - _this.followingsBody.appendChild(li); - } - } - - var url = URI(this.server + "/followings"); - url.addSearch("limit", 200); - APICalls.http_call(url.toString(), "GET", callback, null, false); - } - - Profile.prototype.showFollowers = function() { - - this.showList(this.followersBody); - this.followersBody.innerHTML = ""; - - var _this = this; - var callback = function(resp) { - var followers = JSON.parse(resp.responseText); - for (var i = 0; i < followers.length; i++) { - var li = _this.getDOMSmallProfile(followers[i]); - _this.followersBody.appendChild(li); - } - } - - var url = URI(this.server + "/followers"); - url.addSearch("limit", 200); - APICalls.http_call(url.toString(), "GET", callback, null, false); - } - - Profile.prototype.getDOMSmallProfile = function(profile) { - - var li = document.createElement("li"); - - var image = document.createElement("img"); - image.title = profile.entity; - image.className = "image"; - image.src = 'img/default-avatar.png'; - li.appendChild(image); - image.onclick = function(e) { - HostApp.showProfileForEntity(e.target.title); - return false; - } - - var div = document.createElement("div"); - div.className = "data" - - var h1 = document.createElement("h1"); - var username = document.createElement("a"); - username.title = profile.entity; - username.className = "name"; - username.href = profile.entity; - username.onclick = function(e) { - HostApp.showProfileForEntity(profile.entity); - return false; - } - - h1.appendChild(username) - div.appendChild(h1); - li.appendChild(div); - - var p = document.createElement("p"); - p.className = "message"; - - var entity_tag = document.createElement("a"); - entity_tag.innerText = profile.entity; - entity_tag.href = profile.entity; - entity_tag.title = profile.entity; - - var new_line = document.createElement("br"); - var follows_since = document.createTextNode("follows since "); - var follows_since_time = document.createElement("span"); - follows_since_time.innerText = this.ISODateString(new Date(profile.created_at * 1000)); - follows_since_time.title = follows_since_time.innerText; - follows_since_time.className = "timeago"; - jQuery(follows_since_time).timeago(); - - p.appendChild(entity_tag); - p.appendChild(new_line); - p.appendChild(follows_since); - p.appendChild(follows_since_time); - div.appendChild(p); - - var profile_callback = function(p) { - - var basic = p["https://tent.io/types/info/basic/v0.1.0"]; - - if (p && basic) { - if(basic.name) { - username.title = username.innerText; - username.innerText = basic.name; - } - if(basic.avatar_url) { - image.onerror = function() { image.src = 'img/default-avatar.png'; }; - image.src = basic.avatar_url; - } - } - - } - - var p = this.cache.profiles.getItem(profile.entity); - - if (p && p != "null") { - - profile_callback(p); + Profile.prototype.show = function() { + Core.prototype.show.call(this, this.container); + } - } else { - - var _this = this; - APICalls.findProfileURL(profile.entity, function(profile_url) { + Profile.prototype.hide = function() { + Core.prototype.hide.call(this, this.container); + } - if (profile_url) { - APICalls.http_call(profile_url, "GET", function(resp) { - var p = JSON.parse(resp.responseText); - if (p && p != "null") { - _this.cache.profiles.setItem(profile.entity, p); - profile_callback(p); - } - - }, null, false); // do not send auth-headers - } - }); - } + Profile.prototype.logout = function() { + this.container = ""; + } - return li; - } + Profile.prototype.showList = function(list) { + $(this.body).hide(); + $(this.followingsBody).hide(); + $(this.followersBody).hide(); + $(list).show(); + }; + + Profile.prototype.showProfileForEntity = function(entity) { + if (!entity) { + entity = HostApp.stringForKey("entity"); + }; + + this.clear(); + this.entity = entity; + this.following = null; + this.following_id = null; + this.profile_template.entity.innerHTML = this.entity; + this.profile_template.entity.href = this.entity; + + this.getProfile(); + this.getFollowing(); + } + + Profile.prototype.initProfileTemplate = function() { + + var _this = this; + + var header = document.createElement("header"); + header.className = "profile"; + + this.container.appendChild(header); + this.profile_template = { + avatar: document.createElement("img"), + name: document.createElement("h1"), + entity: document.createElement("a"), + bio: document.createElement("p"), + relationships: document.createElement("td"), + posts: document.createElement("a"), + following: document.createElement("a"), + followed: document.createElement("a"), + birthdate: document.createElement("td"), + location: document.createElement("td"), + gender: document.createElement("td"), + url: document.createElement("a"), + following_button: document.createElement("button"), + mention_button: document.createElement("button") + }; + header.appendChild(this.profile_template.avatar); + this.profile_template.avatar.src = "img/default-avatar.png"; - return Profile; + var div = document.createElement("div"); + header.appendChild(div); + + this.profile_template.following_button.onclick = function(e) { + _this.toggleFollow() + } + div.appendChild(this.profile_template.following_button); + + this.profile_template.mention_button.onclick = function() { + var e = _this.entity; + if (e.startsWith("https://")) { + e = e.substr(8, e.length); + } + HostApp.openNewMessageWidow(null, null, "^" + e + " ", false); + } + div.appendChild(this.profile_template.mention_button); + this.profile_template.mention_button.innerHTML = "Mention"; + + div.appendChild(this.profile_template.name); + + var p = document.createElement("p"); + p.appendChild(this.profile_template.entity); + div.appendChild(p); + + div.appendChild(this.profile_template.bio); + + var table = document.createElement("table"); + div.appendChild(table); + + function mkLi(name, template) { + var tr = document.createElement("tr"); + var th = document.createElement("th"); + tr.style.display = "none"; + th.innerText = name + ": "; + tr.appendChild(th); + tr.appendChild(template); + table.appendChild(tr); + } + + mkLi("Birth date", this.profile_template.birthdate); + mkLi("Location", this.profile_template.location); + mkLi("Gender", this.profile_template.gender); + + var td = document.createElement("td"); + td.appendChild(this.profile_template.url); + mkLi("Homepage", td); + + mkLi("Relationships", this.profile_template.relationships); + + td = document.createElement("td"); + td.appendChild(this.profile_template.posts); + this.profile_template.posts.href = "#"; + this.profile_template.posts.onclick = function() { _this.showPosts(); return false; }; + mkLi("Posts", td); + + td = document.createElement("td"); + td.appendChild(this.profile_template.following); + this.profile_template.following.href = "#"; + this.profile_template.following.onclick = function() { _this.showFollowings(); return false; }; + mkLi("Following", td); + + td = document.createElement("td"); + td.appendChild(this.profile_template.followed); + this.profile_template.followed.href = "#"; + this.profile_template.followed.onclick = function() { _this.showFollowers(); return false; }; + mkLi("Followed by", td); + + + this.body = document.createElement("ol"); + this.body.className = this.action; + this.container.appendChild(this.body); + + this.followingsBody = document.createElement("ol"); + this.followingsBody.className = this.action + " followings"; + this.container.appendChild(this.followingsBody); + + this.followersBody = document.createElement("ol"); + this.followersBody.className = this.action + " folloewds"; + this.container.appendChild(this.followersBody); + + } + + Profile.prototype.clear = function() { + + this.server = null; + + this.profile_template.avatar.src = "img/default-avatar.png"; + + this.relationships = { + following_you: false, + followed_by_you: false, + it_is_you: false + } + + this.profile_template.name.innerText = ""; + this.profile_template.entity.innerText = ""; + this.profile_template.bio.innerText = ""; + this.profile_template.relationships.innerText = ""; + this.profile_template.posts.innerText = ""; + this.profile_template.following.innerText = ""; + this.profile_template.followed.innerText = ""; + this.profile_template.birthdate.innerText = ""; + this.profile_template.location.innerText = ""; + this.profile_template.gender.innerText = ""; + this.profile_template.url.innerText = ""; + this.profile_template.url.href = ""; + + this.profile_template.posts.parentNode.parentNode.style.display = "none"; + this.profile_template.following.parentNode.parentNode.style.display = "none"; + this.profile_template.followed.parentNode.parentNode.style.display = "none"; + this.profile_template.birthdate.parentNode.style.display = "none"; + this.profile_template.location.parentNode.style.display = "none"; + this.profile_template.gender.parentNode.style.display = "none"; + this.profile_template.url.parentNode.parentNode.style.display = "none"; + + this.profile_template.following_button.style.display = ""; + this.setFollowingButton(false); + + this.body.innerHTML = ""; + this.followingsBody.innerHTML = ""; + this.followersBody.innerHTML = ""; + + this.showList(this.body); + }; + + Profile.prototype.getProfile = function() { + + var _this = this; + + if (HostApp.stringForKey("entity") == this.entity) { + this.relationships.it_is_you = true; + this.profile_template.following_button.style.display = "none"; + } + + var profile = this.cache.profiles.getItem(this.entity); + + if (profile && profile != "null") { + + this.showProfile(profile); + this.profile = profile; + + } else { + Paths.findProfileURL(this.entity, function(profile_url) { + + if (profile_url) { + + Paths.getURL(profile_url, "GET", function(resp) { + + profile = JSON.parse(resp.responseText); + _this.showProfile(profile); + _this.profile = profile; + + }, null, false); // do not send auth-headers + } + }); + + } + } + + Profile.prototype.getFollowing = function() { + if(this.entity != HostApp.stringForKey("entity")) { + var url = Paths.mkApiRootPath("/followings") + "/" + encodeURIComponent(this.entity); + var _this = this; + Paths.getURL(url, "GET", function(resp) { + if (resp.status >= 200 && resp.status < 400) { + var following = JSON.parse(resp.responseText); + _this.following_id = following.id + _this.setFollowingButton(true); + } else { + _this.setFollowingButton(false); + _this.following_id = null; + } + }) + } else { + this.setFollowingButton(false); + this.following_id = null; + } + } + + Profile.prototype.showProfile = function(profile) { + + var basic = profile["https://tent.io/types/info/basic/v0.1.0"]; + + if (profile && basic) { + + if(basic.avatar_url) { + this.profile_template.avatar.onerror = function() { this.profile_template.avatar.src = 'img/default-avatar.png' }; + this.profile_template.avatar.src = basic.avatar_url; + } + + this.populate(this.profile_template.name, basic.name); + this.populate(this.profile_template.birthdate, basic.birthdate); + this.populate(this.profile_template.location, basic.location); + this.populate(this.profile_template.gender, basic.gender); + this.populate(this.profile_template.bio, basic.bio); + + if(basic.website_url) { + + var url = basic.website_url; + this.profile_template.url.innerText = url; + this.profile_template.url.parentNode.parentNode.style.display = ""; + + if (!url.startsWith("http")) { + url = "http://" + url; + } + + this.profile_template.url.href = url; + } + } + + if (profile) { + this.server = profile["https://tent.io/types/info/core/v0.1.0"]["servers"][0]; + this.getMeta(this.server); + this.getStatuses(this.server); + } + } + + Profile.prototype.populate = function(t, v) { + if (v) { + t.innerText = v; + t.parentNode.style.display = ""; + t.parentNode.parentNode.style.display = ""; + } + } + + Profile.prototype.getMeta = function(root_url) { + + var _this = this; + Paths.getURL(URI(root_url + "/followings/count").toString(), "GET", function(resp) { + + _this.populate(_this.profile_template.following, resp.responseText); + }, null, false); + + Paths.getURL(URI(root_url + "/followers/count").toString(), "GET", function(resp) { + + _this.populate(_this.profile_template.followed, resp.responseText); + }, null, false); + + if (this.entity != HostApp.stringForKey("entity")) { + Paths.getURL(URI(root_url + "/followers/" + encodeURIComponent(HostApp.stringForKey("entity"))).toString(), "GET", function(resp) { + if (resp.status == 200) { + _this.relationships.following_you = true; + } + _this.setRelationships(); + + }, null, false); + + Paths.getURL(URI(Paths.mkApiRootPath("/followings/" + encodeURIComponent(this.entity))), "GET", function(resp) { + if (resp.status == 200) { + _this.relationships.followed_by_you = true; + } + _this.setRelationships(); + }); + + } else { + this.setRelationships(); + } + + var url = URI(root_url + "/posts/count"); + var post_types = [ + "https://tent.io/types/post/repost/v0.1.0", + "https://tent.io/types/post/status/v0.1.0", + "https://tent.io/types/post/photo/v0.1.0" + ]; + url.addSearch("post_types", post_types.join(",")); + + Paths.getURL(url.toString(), "GET", function(resp) { + + _this.populate(_this.profile_template.posts, resp.responseText); + }, null, false); + } + + Profile.prototype.setRelationships = function() { + var relation = "none"; + if (this.relationships.it_is_you) { + relation = "it's you"; + } else { + if (this.relationships.following_you && !this.relationships.followed_by_you) { + relation = "is following you"; + } else if (this.relationships.following_you && this.relationships.followed_by_you) { + relation = "you both follow each other"; + } else if (!this.relationships.following_you && this.relationships.followed_by_you) { + relation = "being followed by you"; + } + } + this.populate(this.profile_template.relationships, relation); + } + + + Profile.prototype.getStatuses = function(root_url) { + var _this = this; + + var url = URI(root_url + "/posts"); + url.addSearch("limit", 20); + + var post_types = [ + "https://tent.io/types/post/repost/v0.1.0", + "https://tent.io/types/post/status/v0.1.0", + "https://tent.io/types/post/photo/v0.1.0" + ]; + url.addSearch("post_types", post_types.join(",")); + + Paths.getURL(url.toString(), "GET", function(resp) { + + var statuses = JSON.parse(resp.responseText); + + _this.newStatus(statuses); + + }, null, false); + } + + + Profile.prototype.newStatus = function(statuses) { + if(statuses != null && statuses.length > 0) { + for(var i = statuses.length-1, c=0; i>=c; --i) { + + var status = statuses[i]; + this.since_id = status.id; + this.since_id_entity = status.entity; + + if (status.type == "https://tent.io/types/post/status/v0.1.0" || status.type == "https://tent.io/types/post/photo/v0.1.0") { + + var new_node = this.getStatusDOMElement(status); + + if(this.body.childNodes.length > 0) { + + if(this.body.childNodes.length > this.max_length) { + + this.body.removeChild(this.body.lastChild); + } + + this.body.insertBefore(new_node, this.body.firstChild); + + } else { + + this.body.appendChild(new_node); + } + + } else if (status.type == "https://tent.io/types/post/delete/v0.1.0") { + + var li = document.getElementById("post-" + status.content.id); + if (li) { + this.body.removeChild(li); + } + } else if (status.type == "https://tent.io/types/post/repost/v0.1.0") { + + this.getRepost(status, this.body.firstChild); + } + + } + } + } + + Profile.prototype.mention = function() { + + } + + Profile.prototype.setFollowingButton = function(following) { + + this.following = following; + + if (following) { + this.profile_template.following_button.className = "following"; + this.profile_template.following_button.innerText = "Unfollow"; + } else { + this.profile_template.following_button.className = ""; + this.profile_template.following_button.innerText = "Follow"; + } + } + + Profile.prototype.toggleFollow = function() { + + var _this = this; + + if (this.following_id) { + + this.setFollowingButton(false); + var url = Paths.mkApiRootPath("/followings/") + this.following_id; + Paths.getURL(url, "DELETE", function(resp) { + if (resp.status >= 200 && resp.status < 300) { + _this.setFollowingButton(false); + _this.following_id = null; + } else { + _this.setFollowingButton(true); + } + }); + + } else { + + this.setFollowingButton(true); + var url = URI(Paths.mkApiRootPath("/followings")); + var data = JSON.stringify({"entity": this.entity }); + + Paths.getURL(url.toString(), "POST", function(resp) { + if (resp.status >= 200 && resp.status < 300) { + _this.following_id = JSON.parse(resp.responseText).id + _this.setFollowingButton(true); + } else { + _this.setFollowingButton(false); + } + }, data); + } + } + + Profile.prototype.showPosts = function() { + this.showList(this.body); + } + + Profile.prototype.showFollowings = function() { + + this.showList(this.followingsBody); + this.followingsBody.innerHTML = ""; + + var _this = this; + var callback = function(resp) { + var followings = JSON.parse(resp.responseText); + for (var i = 0; i < followings.length; i++) { + var li = _this.getDOMSmallProfile(followings[i]); + _this.followingsBody.appendChild(li); + } + } + + var url = URI(this.server + "/followings"); + url.addSearch("limit", 200); + Paths.getURL(url.toString(), "GET", callback, null, false); + } + + Profile.prototype.showFollowers = function() { + + this.showList(this.followersBody); + this.followersBody.innerHTML = ""; + + var _this = this; + var callback = function(resp) { + var followers = JSON.parse(resp.responseText); + for (var i = 0; i < followers.length; i++) { + var li = _this.getDOMSmallProfile(followers[i]); + _this.followersBody.appendChild(li); + } + } + + var url = URI(this.server + "/followers"); + url.addSearch("limit", 200); + Paths.getURL(url.toString(), "GET", callback, null, false); + } + + Profile.prototype.getDOMSmallProfile = function(profile) { + + var li = document.createElement("li"); + + var image = document.createElement("img"); + image.title = profile.entity; + image.className = "image"; + image.src = 'img/default-avatar.png'; + li.appendChild(image); + image.onclick = function(e) { + HostApp.showProfileForEntity(e.target.title); + return false; + } + + var div = document.createElement("div"); + div.className = "data" + + var h1 = document.createElement("h1"); + var username = document.createElement("a"); + username.title = profile.entity; + username.className = "name"; + username.href = profile.entity; + username.onclick = function(e) { + HostApp.showProfileForEntity(profile.entity); + return false; + } + + h1.appendChild(username) + div.appendChild(h1); + li.appendChild(div); + + var p = document.createElement("p"); + p.className = "message"; + + var entity_tag = document.createElement("a"); + entity_tag.innerText = profile.entity; + entity_tag.href = profile.entity; + entity_tag.title = profile.entity; + + var new_line = document.createElement("br"); + var follows_since = document.createTextNode("follows since "); + var follows_since_time = document.createElement("span"); + follows_since_time.innerText = this.ISODateString(new Date(profile.created_at * 1000)); + follows_since_time.title = follows_since_time.innerText; + follows_since_time.className = "timeago"; + jQuery(follows_since_time).timeago(); + + p.appendChild(entity_tag); + p.appendChild(new_line); + p.appendChild(follows_since); + p.appendChild(follows_since_time); + div.appendChild(p); + + var profile_callback = function(p) { + + var basic = p["https://tent.io/types/info/basic/v0.1.0"]; + + if (p && basic) { + if(basic.name) { + username.title = username.innerText; + username.innerText = basic.name; + } + if(basic.avatar_url) { + image.onerror = function() { image.src = 'img/default-avatar.png'; }; + image.src = basic.avatar_url; + } + } + + } + + var p = this.cache.profiles.getItem(profile.entity); + + if (p && p != "null") { + + profile_callback(p); + + } else { + + var _this = this; + Paths.findProfileURL(profile.entity, function(profile_url) { + + if (profile_url) { + Paths.getURL(profile_url, "GET", function(resp) { + var p = JSON.parse(resp.responseText); + if (p && p != "null") { + _this.cache.profiles.setItem(profile.entity, p); + profile_callback(p); + } + + }, null, false); // do not send auth-headers + } + }); + } + + return li; + } + + + return Profile; }); diff --git a/WebKit/scripts/controller/Search.js b/WebKit/scripts/controller/Search.js index b083362..62b19a5 100644 --- a/WebKit/scripts/controller/Search.js +++ b/WebKit/scripts/controller/Search.js @@ -1,11 +1,11 @@ define([ "helper/HostApp", "helper/Core", - "helper/APICalls", + "helper/Paths", "lib/URI" ], -function(HostApp, Core, APICalls, URI) { +function(HostApp, Core, Paths, URI) { function Search() { @@ -14,10 +14,7 @@ function(HostApp, Core, APICalls, URI) { this.action = "search"; - this.offset = 0; - this.container = document.createElement("div"); - this.container.className = this.action; document.getElementById("content").appendChild(this.container); this.body = document.createElement("ol"); @@ -26,17 +23,11 @@ function(HostApp, Core, APICalls, URI) { this.form.className = this.action; this.input = document.createElement("input"); this.input.type = "search"; - this.input.placeholder = "Search"; + this.input.placeholder = "Search ..."; this.form.appendChild(this.input); - this.before = {loading: false}; - var _this = this; - this.form.onsubmit = function() { - _this.offset = 0; - _this.before = {loading: false}; - _this.doSearch(_this.input.value); return false; - }; + this.form.onsubmit = function() { _this.doSearch(_this.input.value); return false; }; this.form.action = "#"; this.container.appendChild(this.form); @@ -57,11 +48,9 @@ function(HostApp, Core, APICalls, URI) { Core.prototype.hide.call(this, this.container); } - Search.prototype.doSearch = function(query, add_search, append) { + Search.prototype.doSearch = function(query) { - add_search = add_search || {}; - - if(!append) this.body.innerHTML = ""; // remove old results + this.body.innerHTML = ""; // remove old results if (query == "") return; this.input.value = query; @@ -73,74 +62,45 @@ function(HostApp, Core, APICalls, URI) { url.addSearch("api_key", api_key); url.addSearch("text", query); - for (key in add_search) { - url.addSearch(key, add_search[key]); - } - var _this = this; - APICalls.http_call(url.toString(), "GET", function(resp) { + Paths.getURL(url.toString(), "GET", function(resp) { var results = JSON.parse(resp.responseText).results; - if (results && results.length > 0) { - - _this.before.loading = false; - - var statuses = []; - for (var i = 0; i < results.length; i++) { - var result = results[i].source; - var status = { - entity: result.entity, - content: { - text: result.content - }, - published_at: result.published_at, - id: result.public_id, - type: result.post_type, - version: result.post_version, - app: { - url: "http://skate.io", - name: "skate.io" - }, - mentions: [] - } - - statuses.push(status); + var statuses = []; + for (var i = 0; i < results.length; i++) { + var result = results[i].source; + var status = { + entity: result.entity, + content: { + text: result.content + }, + published_at: result.published_at, + id: result.public_id, + type: result.post_type, + version: result.post_version, + app: { + url: "http://skate.io", + name: "skate.io" + }, + mentions: [] } - for(var i = 0; i < statuses.length; i++) { - var status = statuses[i]; - if (status.type == "https://tent.io/types/post/status/v0.1.0") { + statuses.push(status); + } - var new_node = _this.getStatusDOMElement(status); - _this.body.appendChild(new_node); - } + for(var i = 0; i < statuses.length; i++) { + var status = statuses[i]; + if (status.type == "https://tent.io/types/post/status/v0.1.0") { + + var new_node = _this.getStatusDOMElement(status); + _this.body.appendChild(new_node); } - } else { - var noresult = document.createElement("p"); - noresult.className = "noresult"; - noresult.textContent = "No Results"; - _this.body.appendChild(noresult); } }, null, false); } - Search.prototype.getMoreStatusPosts = function() { - - if (!this.before.loading) { - - this.offset += 20; - - this.before.loading = true; - var add_search = { - "offset": this.offset - } - - this.doSearch(this.input.value, add_search, true); - } - } - Search.prototype.searchFor = function(query) { this.doSearch(query); bungloo.sidebar.onSearch(); diff --git a/WebKit/scripts/controller/Sidebar.js b/WebKit/scripts/controller/Sidebar.js index 4c150ef..81d5599 100644 --- a/WebKit/scripts/controller/Sidebar.js +++ b/WebKit/scripts/controller/Sidebar.js @@ -1,13 +1,16 @@ define([ "helper/HostApp", - "helper/APICalls", + "helper/Paths", + "helper/Cache" ], -function(HostApp, APICalls) { +function(HostApp, Paths, Cache) { function Sidebar() { + this.cache = new Cache(); + this.body = document.createElement("ul"); this.body.class = "sidebar"; @@ -17,39 +20,27 @@ function(HostApp, APICalls) { this.menu.user = this.createItem("User", function() { _this.onEntity(); return false; }, "img/sidebar/user.png", "img/sidebar/user.png"); this.menu.timeline = this.createItem("Timeline", function() { _this.onTimeline(); return false; }, "img/sidebar/timeline.png", "img/sidebar/timeline_active.png", true); - this.menu.mentions = this.createItem("Mentions", function() { _this.onMentions(); return false; }, "img/sidebar/mentions.png", "img/sidebar/mentions_active.png"); + this.menu.mentions = this.createItem("Mentions", function() { _this.onMentions(); return false; }, "img/sidebar/mentions.png", "img/sidebar/mentions_active.png"); + this.menu.conversation = this.createItem("Conversation", function() { _this.onConversation(); return false; }, "img/sidebar/conversation.png", "img/sidebar/conversation_active.png"); this.menu.entityProfile = this.createItem("Profile", function() { _this.onEntityProfile(); return false; }, "img/sidebar/profile.png", "img/sidebar/profile_active.png"); - // FIXME when skate.io is available again: this.menu.search = this.createItem("Search", function() { _this.onSearch(); return false; }, "img/sidebar/search.png", "img/sidebar/search_active.png") + this.menu.search = this.createItem("Search", function() { _this.onSearch(); return false; }, "img/sidebar/search.png", "img/sidebar/search_active.png") this.body.appendChild(this.menu.user); this.body.appendChild(this.menu.timeline); this.body.appendChild(this.menu.mentions); this.body.appendChild(this.menu.conversation); this.body.appendChild(this.menu.entityProfile); - //this.body.appendChild(this.menu.search); + this.body.appendChild(this.menu.search); this.unreadMentionsSpan = document.createElement("span"); this.unreadMentionsSpan.className = "unread_mentions"; - this.menu.mentions.getElementsByTagName("a")[0].appendChild(this.unreadMentionsSpan); + this.menu.mentions.appendChild(this.unreadMentionsSpan); this.setUnreadMentions(0); - this.menu.conversation.getElementsByTagName("a")[0].ondblclick = function() { - var postId = bungloo.conversation.current_post_id; - var entity = bungloo.conversation.current_entity; - if (postId && entity) { - HostApp.showConversationViewForPostIdandEntity(postId, entity); - } - } - document.getElementById("sidebar").appendChild(this.body); - // initial seting of the class - document.body.className = "body-timeline"; - document.body.id = "with-sidebar"; - this.setEntityAvatar(); - this.setOnScroll(); } Sidebar.prototype.createItem = function(name, callback, src_inactive, src_active, active) { @@ -81,39 +72,57 @@ function(HostApp, APICalls) { var entity = HostApp.stringForKey("entity"); this.menu.user.title = entity; - var avatar = this.menu.user.getElementsByTagName("img")[0]; + var img = this.menu.user.getElementsByTagName("img")[0]; + var _this = this; - var url = HostApp.serverUrl("posts_feed") + "?types=" + encodeURIComponent("https://tent.io/types/meta/v0") + "&entities=" + encodeURIComponent(entity); - APICalls.get(url, { callback: function(resp) { - var profiles = JSON.parse(resp.responseText); + var profile_callback = function(p) { - if(profiles.posts.length < 1) return; - var profile = profiles.posts[0]; - bungloo.cache.profiles[entity] = profile; + var basic = p["https://tent.io/types/info/basic/v0.1.0"]; - // Find and apply avatar - if(profile.attachments) { - - var digest = null; - for (var i = 0; i < profile.attachments.length; i++) { - var attachment = profile.attachments[i]; - if(attachment.category == "avatar") { - digest = attachment.digest; - break; - } + if (p && basic) { + if(basic.name) { + _this.menu.user.title = basic.name; } + if(basic.avatar_url) { + + img.onerror = function() { + img.src = "img/sidebar/user.png"; + img.src_inactive = img.src; + img.src_active = img.src; + } + + img.src = basic.avatar_url; + img.src_inactive = basic.avatar_url; + img.src_active = basic.avatar_url; - if(digest) { - var _this = this; - avatar.onerror = function() { avatar.src = 'img/default-avatar.png' }; - var avatar_url = profile.content.servers[0].urls.attachment.replace(/\{entity\}/, encodeURIComponent(profile.entity)); - avatar.src = avatar_url.replace(/\{digest\}/, digest); - avatar.src_inactive = avatar.src; - avatar.src_active = avatar.src; } } - }}); + + } + + var p = this.cache.profiles.getItem(entity); + + if (p && p != "null") { + + profile_callback(p); + + } else { + + Paths.findProfileURL(entity, function(profile_url) { + + if (profile_url) { + Paths.getURL(profile_url, "GET", function(resp) { + var p = JSON.parse(resp.responseText); + if (p && p != "null") { + _this.cache.profiles.setItem(entity, p); + profile_callback(p); + } + + }, null, false); // do not send auth-headers + } + }); + } } Sidebar.prototype.removeEntityAvatar = function() { @@ -141,10 +150,6 @@ function(HostApp, APICalls) { } active_part.show(); - this.active_view = active_part; - - // Replace class - document.body.className = "body-" + active_li.className.split("-")[1]; // Show active icon for(var li in this.menu) { @@ -158,48 +163,6 @@ function(HostApp, APICalls) { img.src = img.src_active; } - Sidebar.prototype.showContentForNext = function() { - - var parts = [ - "timeline", - "mentions", - "conversation", - "entityProfile", - "search" - ]; - - for (var i = 0; i < parts.length; i++) { - var part = parts[i]; - var img = this.menu[part].getElementsByTagName("img")[0]; - if (img.src.endsWith(img.src_active)) { - var next = parts[(i+1)%parts.length]; - //we must update unread badges for mentions cf https://github.com/jeena/Bungloo/issues/222 - if(next === "mentions"){ - bungloo.mentions.setAllMentionsRead(); - } - this.showContentFor(bungloo[next], this.menu[next]); - return; - } - } - } - - Sidebar.prototype.showContentForTimeline = function() { - this.showContentFor(bungloo.timeline, this.menu.timeline); - } - - // runs get more posts when scrolling down and - // it is possible for the active view - Sidebar.prototype.setOnScroll = function() { - var _this = this; - window.onscroll = function() { - if (document.body.scrollHeight <= (document.body.scrollTop + window.outerHeight)) { - if (typeof _this.active_view["getMoreStatusPosts"] != "undefined") { - _this.active_view.getMoreStatusPosts(); - } - } - } - } - Sidebar.prototype.setUnreadMentions = function(count) { this.unreadMentionsSpan.innerHTML = count == 0 ? "" : count; if (count > 0) { diff --git a/WebKit/scripts/controller/Timeline.js b/WebKit/scripts/controller/Timeline.js index da16564..4888ee4 100644 --- a/WebKit/scripts/controller/Timeline.js +++ b/WebKit/scripts/controller/Timeline.js @@ -1,11 +1,11 @@ define([ "helper/Core", - "helper/APICalls", + "helper/Paths", "helper/HostApp", "lib/URI" ], -function(Core, APICalls, HostApp, URI) { +function(Core, Paths, HostApp, URI) { function Timeline() { @@ -14,23 +14,15 @@ function(Core, APICalls, HostApp, URI) { this.action = "timeline"; this.reload_blocked = false; - this.posts_limit = 50; this.max_length = 200; this.timeout = 10 * 1000; // every 10 seconds this.since_id = null; this.since_id_entity = null; - this.since_time = null; + this.since_time = 0; - this.pages = {}; - this.next = null; - - this.before = {id: null, entity: null, loading: false}; - - this.container = document.createElement("div"); - this.container.className = this.action; this.body = document.createElement("ol"); - this.container.appendChild(this.body) - document.getElementById("content").appendChild(this.container); + this.body.className = this.action; + document.getElementById("content").appendChild(this.body); var _this = this; this.reloadIntervall = setInterval(function() { _this.getNewData() }, this.timeout); @@ -41,149 +33,103 @@ function(Core, APICalls, HostApp, URI) { Timeline.prototype = Object.create(Core.prototype); Timeline.prototype.show = function() { - Core.prototype.show.call(this, this.container); + Core.prototype.show.call(this, this.body); } Timeline.prototype.hide = function() { - Core.prototype.hide.call(this, this.container); + Core.prototype.hide.call(this, this.body); } - Timeline.prototype.newStatus = function(_statuses, append) { - for (var entity in _statuses.profiles) { - if (_statuses.profiles[entity] != null) { - bungloo.cache.profiles[entity] = _statuses.profiles[entity]; - } else { - bungloo.cache.profiles[entity] = {}; - } - } - - this.pages = _statuses.pages; - if(_statuses.pages.next) this.next = _statuses.pages.next; - - statuses = _statuses.posts; - - this.before.loading = false; + Timeline.prototype.newStatus = function(statuses) { if(statuses != null && statuses.length > 0) { - - if (append) statuses = statuses.reverse(); - for(var i = statuses.length-1, c=0; i>=c; --i) { var status = statuses[i]; - if(!append) { - this.since_id = status.id; - this.since_id_entity = status.entity; - //this.since_time = status.received_at; - this.since_time = status.version.received_at; - } + this.since_id = status.id; + this.since_id_entity = status.entity; - if (status.type.startsWith("https://tent.io/types/status/v0#")) { + if (status.type == "https://tent.io/types/post/status/v0.1.0" || status.type == "https://tent.io/types/post/photo/v0.1.0") { - var new_node = this.getStatusDOMElement(status, _statuses.refs); - var old_node = document.getElementById(new_node.id); - - if (!old_node) { - if(!append && this.body.childNodes.length > 0) { + var new_node = this.getStatusDOMElement(status); - if(this.body.childNodes.length > this.max_length) { + if(this.body.childNodes.length > 0) { - this.body.removeChild(this.body.lastChild); - } + if(this.body.childNodes.length > this.max_length) { - this.body.insertBefore(new_node, this.body.firstChild); - - } else { - - this.body.appendChild(new_node); + this.body.removeChild(this.body.lastChild); } + + this.body.insertBefore(new_node, this.body.firstChild); + } else { - debug(new_node.id); - old_node.parentNode.replaceChild(new_node, old_node); + + this.body.appendChild(new_node); } - } else if (status.type == "https://tent.io/types/delete/v0#") { + } else if (status.type == "https://tent.io/types/post/delete/v0.1.0") { - HostApp.notificateViewsAboutDeletedPost(status.refs[0].post, status.entity); + HostApp.notificateViewsAboutDeletedPost(status.content.id, status.entity); - } else if (status.type.startsWith("https://tent.io/types/repost/v0#")) { - - this.getRepost(status, append ? this.body.lastChild : this.body.firstChild, append); + } else if (status.type == "https://tent.io/types/post/repost/v0.1.0") { + this.getRepost(status, this.body.firstChild); } } } } - Timeline.prototype.getNewData = function(add_to_search, append, query) { + Timeline.prototype.getNewData = function(add_to_search) { add_to_search = add_to_search || {}; var those = this; - var url = HostApp.serverUrl("posts_feed"); + var url = URI(Paths.mkApiRootPath("/posts")); - if(!query) { + var post_types = [ + "https://tent.io/types/post/repost/v0.1.0", + "https://tent.io/types/post/status/v0.1.0", + "https://tent.io/types/post/delete/v0.1.0", + "https://tent.io/types/post/photo/v0.1.0" + ]; + url.addSearch("post_types", post_types.join(",")); - var uri = URI(url); + url.addSearch("limit", this.max_length); - var post_types = [ - "https://tent.io/types/status/v0#", - "https://tent.io/types/status/v0#reply", - "https://tent.io/types/repost/v0#https://tent.io/types/status/v0", - "https://tent.io/types/delete/v0#", - //"https://tent.io/types/post/photo/v0.1.0" - ]; - uri.addSearch("types", post_types.join(",")); - //uri.addSearch("sort_by", "published_at"); - uri.addSearch("limit", this.posts_limit); - uri.addSearch("max_refs", 20); - uri.addSearch("profiles", "entity"); - uri.addSearch("sort_by", "version.received_at"); - - if(this.since_time) { - uri.addSearch("since", this.since_time); - } - - for (key in add_to_search) { - uri.addSearch(key, add_to_search[key]); - } - - url = uri.toString(); - - } else { - url += query; + if(this.since_id) { + url.addSearch("since_id", this.since_id); + url.addSearch("since_id_entity", this.since_id_entity); } + for (key in add_to_search) { + url.addSearch(key, add_to_search[key]); + } + + var http_method = "GET"; + var callback = function(resp) { + + those.reload_blocked = false; + + try { + + var json = JSON.parse(resp.responseText) + those.newStatus(json); + + } catch (e) { + console.error(url + " JSON parse error"); + throw e; + } + } + + var data = null; + if (HostApp.stringForKey("user_access_token")) { if (!this.reload_blocked) { this.reload_blocked = true; - - APICalls.get(url, { callback: function(resp) { - // FIXME this is getting data when it shouldn't debug(resp.responseText) - - those.reload_blocked = false; - - try { - var json = JSON.parse(resp.responseText); - those.newStatus(json, append); - - } catch (e) { - console.error(url + " JSON parse error"); - throw e; - } - } }); - } - } - } - - Timeline.prototype.getMoreStatusPosts = function() { - if (!this.before.loading) { - if (this.next) { - this.before.loading = true; - this.getNewData({}, true, this.next); + Paths.getURL(url.toString(), http_method, callback, data); // FIXME: error callback } } } diff --git a/WebKit/scripts/helper/APICalls.js b/WebKit/scripts/helper/APICalls.js deleted file mode 100644 index 202a7cb..0000000 --- a/WebKit/scripts/helper/APICalls.js +++ /dev/null @@ -1,318 +0,0 @@ -define([ - "jquery", - "helper/HostApp", - "helper/Hmac", - "helper/Cache" -], - -function(jQuery, HostApp, Hmac, Cache) { - var APICalls = {}; - - APICalls.cache = new Cache(); - - APICalls.getUrlVars = function(url) { - var vars = [], hash; - if(url.indexOf("#") > -1) url = url.slice(0, url.indexOf("#")); - var hashes = url.slice(url.indexOf('?') + 1).split('&'); - for(var i = 0; i < hashes.length; i++) - { - hash = hashes[i].split('='); - vars.push(hash[0]); - vars[hash[0]] = hash[1]; - } - return vars; - } - - APICalls.http_call = function(options) { - - if (typeof options === "string") { - console.error(options + " not implemented yet") - return; - } - - var content_type = null; - - if((options.http_method == "POST" || options.http_method == "PUT") && !options.content_type) { - console.error("No content type for " + options.url); - return; - - } else { - if(options.content_type == "application/json") { - content_type = "application/json"; - } else if(options.content_type) { - content_type = "application/vnd.tent.post.v0+json; charset=UTF-8; type=\"" + options.content_type + "\""; - } - } - - var settings = { - beforeSend: function(xhr) { - if (options.data) xhr.setRequestHeader("Content-Length", options.data.length); - - if (options.accept) xhr.setRequestHeader("Accept", options.accept); - else xhr.setRequestHeader("Accept", "application/vnd.tent.post.v0+json"); - - var user_access_token = HostApp.stringForKey("user_access_token"); - if (!options.auth_header && !options.no_auth && user_access_token) { - var auth_header = Hmac.makeHawkAuthHeader( - options.url, - options.http_method, - user_access_token, - HostApp.secret()//, - //HostApp.stringForKey("app_id") - ); - xhr.setRequestHeader("Authorization", auth_header); - } else if(options.auth_header) { - xhr.setRequestHeader("Authorization", options.auth_header); - } else if(!options.no_auth) { - console.error("No user_access_token yet - " + options.url); - } - xhr.setRequestHeader("Cache-Control", "no-proxy"); - }, - url: options.url, - contentType: content_type, - type: options.http_method, - complete: options.callback, - data: options.data, - processData: false, - error: function(xhr, ajaxOptions, thrownError) { - console.error("HTTP CALL (" + xhr.status + ") " + xhr.statusText + " " + options.http_method + " URL(" + options.url + "): '" + xhr.responseText + "'"); - } - }; - - jQuery.ajax(settings); - } - - APICalls.head = function(url, options) { - var settings = { - url: url, - http_method: "HEAD", - }; - - for (var key in options) { - settings[key] = options[key]; - } - - APICalls.http_call(settings); - } - - APICalls.get = function(url, options) { - var settings = { - url: url, - http_method: "GET", - }; - - for (var key in options) { - settings[key] = options[key]; - } - - APICalls.http_call(settings); - } - - APICalls.post = function(url, data, options) { - var settings = { - url: url, - http_method: "POST", - data: data - }; - - for (var key in options) { - settings[key] = options[key]; - } - - APICalls.http_call(settings); - } - - APICalls.delete = function(url, options) { - var settings = { - url: url, - http_method: "DELETE" - }; - - for (var key in options) { - settings[key] = options[key]; - } - - APICalls.http_call(settings); - } - - APICalls.put = function(url, data, options) { - var settings = { - url: url, - http_method: "PUT", - data: data - }; - - for (var key in options) { - settings[key] = options[key]; - } - - APICalls.http_call(settings); - } - - - APICalls.postMultipart = function(url, callback, data, boundary, accepts) { - - accepts = accepts || "application/vnd.tent.v0+json"; - - jQuery.ajax({ - - beforeSend: function(xhr) { - xhr.setRequestHeader("Accept", accepts); - - if (data) xhr.setRequestHeader("Content-Length", data.length); - - var user_access_token = HostApp.stringForKey("user_access_token"); - - if (user_access_token) { - - auth_header = Hmac.makeAuthHeader( - url, - "POST", - HostApp.secret(), - user_access_token - ); - - xhr.setRequestHeader("Authorization", auth_header); - } - }, - url: url, - contentType: "multipart/form-data;boundary=" + boundary, - type: "POST", - complete: callback, - data: data, - processData: false, - error: function(xhr, ajaxOptions, thrownError) { - console.error("postMultipart (" + xhr.status + ")" + xhr.statusText + " (" + url + "): '" + xhr.responseText + "'"); - } - }); - } - - APICalls.findProfileURL = function(entity, callback, errorCallback) { - var profile_url = APICalls.cache.profile_urls.getItem(entity); - - if (profile_url && profile_url != "null") { - - callback(profile_url); - - } else { - - jQuery.ajax({ - url: entity, - type: "HEAD", - complete: function(resp) { - if(resp) { - var headers = resp.getAllResponseHeaders(); - - var profile_urls = APICalls.parseHeaderForProfiles(headers); - var profile_url = null; - if(profile_urls.length > 0) { - var profile_url = profile_urls[0]; - if (!profile_url.startsWith("http")) { - profile_url = entity + profile_url; - } - } - - if (profile_url) { - APICalls.cache.profile_urls.setItem(entity, profile_url); - callback(profile_url); - } else { - APICalls.http_call(entity, "GET", function(resp) { - - if (resp.status >= 200 && resp.status < 300) { - var doc = document.implementation.createHTMLDocument(""); - doc.documentElement.innerHTML = resp.responseText; - var links = $(doc).find("link[rel='https://tent.io/rels/meta-post']"); - - if (links.length > 0) { - var href = links.get(0).href; - APICalls.cache.profile_urls.setItem(entity, href); - if (!href.startsWith("http")) { - href = entity + href; - } - callback(href); - - } else { - if(errorCallback) errorCallback(entity + " has no profile URL"); - } - } else { - if(errorCallback) errorCallback(entity + " has no profile URL"); - } - - }, null, false, false); - - //if(errorCallback) errorCallback(entity + " has no profile URL"); - } - } - }, - error: function(xhr, ajaxOptions, thrownError) { - console.error("findProfileURL " + xhr.statusText + " (" + entity + "): " + xhr.responseText); - if (errorCallback) errorCallback(xhr.statusText + " - " + xhr.responseText) - } - }); - } - } - - APICalls.mkApiRootPath = function(path) { - - var api_root = HostApp.stringForKey("api_root"); - - if((api_root.substring(api_root.length - 1, api_root.length) != "/") && (path.substring(0, 1) != "/")) { - api_root += "/"; - } else if((api_root.substring(api_root.length - 1, api_root.length) == "/") && (path.substring(0, 1) == "/")) { - api_root = api_root.substring(0, api_root.length -1); - } - return api_root + path; - } - - APICalls.parseHeaderForProfiles = function(header_string) { - var regexp = /https:\/\/tent.io\/rels\/meta-post/i; - return APICalls.parseHeaderForLink(header_string, regexp); - } - - APICalls.parseHeader = function(header_string) { - var header_strings = header_string.split(/\n/); - var headers = {}; - for (var i = 0; i < header_strings.length; i++) { - var hs = header_strings[i].split(/:(.+)?/); - headers[hs[0]] = hs[1]; - } - return headers; - } - - APICalls.getCount = function(resp) { - var count = 0; - var headers = APICalls.parseHeader(resp.getAllResponseHeaders()); - if(headers["Count"]) count = parseInt(headers["Count"], 10); - return count; - } - - APICalls.parseHeaderForLink = function(header_string, match) { - var headers = header_string.split(/\n/); - var links = []; - for (var i = 0; i < headers.length; i++) { - var header = headers[i]; - if (header.match(/^Link:(.*)/i)) { - links.push(header.replace(/\r/, "").substr(5).trim()); - } - } - - var items = []; - for (var i = 0; i < links.length; i++) { - items = items.concat(links[i].split(",")); - } - var things = []; - for (var i = 0; i < items.length; i++) { - var item = items[i]; - if (item.match(match)) { - var n = item.match(/<([^>]*)>/); - if (n) { - things.push(n[1]); - } - } - } - - return things; - } - - return APICalls; -}); \ No newline at end of file diff --git a/WebKit/scripts/helper/Cache.js b/WebKit/scripts/helper/Cache.js index 2b35364..eb79fe7 100644 --- a/WebKit/scripts/helper/Cache.js +++ b/WebKit/scripts/helper/Cache.js @@ -40,12 +40,12 @@ function(URI, CacheStorage, require) { } } - var url = URI(require("helper/APICalls").mkApiRootPath("/followings")); + var url = URI(require("helper/Paths").mkApiRootPath("/followings")); if (this.followings_before_id) { url.addSearch("before_id", this.followings_before_id); } - require("helper/APICalls").getURL(url, "GET", callback); + require("helper/Paths").getURL(url, "GET", callback); } Cache.prototype.periodicallyGetFollowings = function() { diff --git a/WebKit/scripts/helper/ConversationNode.js b/WebKit/scripts/helper/ConversationNode.js deleted file mode 100644 index 64c882c..0000000 --- a/WebKit/scripts/helper/ConversationNode.js +++ /dev/null @@ -1,25 +0,0 @@ -define([ - -], - -function() { - - - function ConversationNode(dom_node) { - this.dom_node = dom_node; - this.parent = null; - this.children = []; - } - - ConversationNode.prototype.addChild = function(node) { - this.children.push(node); - node.parent = this; - }; - - ConversationNode.prototype.toString = function() { - return "{ \"" + this.dom_node.status.entity + "\": [" + this.children.toString() + "]}"; - }; - - - return ConversationNode; -}); \ No newline at end of file diff --git a/WebKit/scripts/helper/Core.js b/WebKit/scripts/helper/Core.js index 1a4f25b..c3c3147 100644 --- a/WebKit/scripts/helper/Core.js +++ b/WebKit/scripts/helper/Core.js @@ -1,16 +1,16 @@ define([ "jquery", - "helper/APICalls", + "helper/Paths", "lib/URI", "helper/HostApp", - "lib/Markdown", - "lib/Timeago", - "lib/SingleDoubleClick" + "helper/Cache", + "lib/Timeago" ], -function(jQuery, APICalls, URI, HostApp, Markdown) { +function(jQuery, Paths, URI, HostApp, Cache) { function Core() { + this.cache = new Cache(); this.saveScrollTop = 0; } @@ -37,11 +37,7 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { var a = document.createElement("a"); - var li = document.createElement("li"); - - var item = document.createElement("div"); - item.className = "post"; - li.appendChild(item); + var item = document.createElement("li"); var aside = document.createElement("aside"); item.appendChild(aside); @@ -72,7 +68,6 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { image.className = "image"; image.src = "img/default-avatar.png"; image.onmousedown = function(e) { e.preventDefault(); }; - image.onerror = function() { this.src = 'img/default-avatar.png' }; item.appendChild(image); var image_username = a.cloneNode(); @@ -127,7 +122,7 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { head.appendChild(reposted_by) - var message = document.createElement("div"); + var message = document.createElement("p"); message.className = "message"; data.appendChild(message); @@ -147,7 +142,6 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { from.appendChild(source) this.template = { - li: li, item: item, reply_to: reply_to, is_private: is_private, @@ -166,14 +160,14 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { return jQuery.extend(true, {}, this.template);; } - Core.prototype.getStatusDOMElement = function(status, refs) { + Core.prototype.getStatusDOMElement = function(status) { var _this = this; var template = this.getTemplate(); - template.li.id = "post-" + status.id + "-" + this.action; - template.li.status = status; + template.item.id = "post-" + status.id; + template.item.status = status; if (HostApp.stringForKey("entity") == status.entity && typeof status.__repost == "undefined") { template.remove.onclick = function() { @@ -189,15 +183,10 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { template.remove.style.display = "none"; } - if (HostApp.stringForKey("entity") == status.entity) { - template.li.className += " own"; - } - template.reply_to.onclick = function() { var mentions = []; - var status_mentions = []; - if(status.mentions) status_mentions = status.mentions.slice(0); + var status_mentions = status.mentions.slice(0); if (typeof status.__repost != "undefined") { status_mentions.push({entity:status.__repost.entity}); @@ -208,18 +197,17 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { mentions.push(mention); } - _this.replyTo(status); + _this.replyTo(status.entity, status.id, mentions, (status && status.permissions && !status.permissions.public)); return false; } template.repost.onclick = function() { $(template.repost).hide(); - _this.repost(status); + _this.repost(status.id, status.entity); return false; } - if(bungloo.cache.profiles[status.entity] && bungloo.cache.profiles[status.entity].name) template.username.innerText = bungloo.cache.profiles[status.entity].name; - else template.username.innerText = status.entity; + template.username.innerText = status.entity; template.username.href = status.entity; template.username.title = status.entity; template.username.onclick = function() { @@ -227,12 +215,47 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { return false; } - if(bungloo.cache.profiles[status.entity] && bungloo.cache.profiles[status.entity].avatar_digest) { - template.image.src = HostApp.serverUrl("attachment").replace(/\{entity\}/, encodeURIComponent(status.entity)).replace(/\{digest\}/, bungloo.cache.profiles[status.entity].avatar_digest); - } - template.image.onclick = template.username.onclick; + var profile_callback = function(p) { + + var basic = p["https://tent.io/types/info/basic/v0.1.0"]; + + if (p && basic) { + if(basic.name) { + template.username.title = template.username.innerText; + template.username.innerText = basic.name; + } + if(basic.avatar_url) { + template.image.onerror = function() { template.image.src = 'img/default-avatar.png' }; + template.image.src = basic.avatar_url; + } + } + + } + + var p = this.cache.profiles.getItem(status.entity); + + if (p && p != "null") { + + profile_callback(p); + + } else { + + Paths.findProfileURL(status.entity, function(profile_url) { + + if (profile_url) { + Paths.getURL(profile_url, "GET", function(resp) { + var p = JSON.parse(resp.responseText); + if (p && p != "null") { + _this.cache.profiles.setItem(status.entity, p); + profile_callback(p); + } + + }, null, false); // do not send auth-headers + } + }); + } if (status && status.permissions && !status.permissions.public) { template.is_private.style.display = ''; @@ -240,7 +263,7 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { var text = ""; - if (status.type == "https://tent.io/types/post/photo/v0.1.0") { // FIXME + if (status.type == "https://tent.io/types/post/photo/v0.1.0") { text = status.content.caption; } else { if (status.content && status.content.text) { @@ -250,6 +273,8 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { this.parseForMedia(text, template.images); + text = text.escapeHTML().replace(/\n/g, "
    "); + var entities = [status.entity]; if (status.mentions) { status.mentions.map(function (mention) { @@ -258,37 +283,43 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { } template.message.innerHTML = this.replaceURLWithHTMLLinks(text, entities, template.message); - this.afterChangingTextinMessageHTML(template.message) + + // adding show search on click hash + $(template.message).find("a.hash").click(function(e) { + bungloo.search.searchFor("#" + e.target.innerHTML); + return false; + }); - if(status.refs) { - for (var i = 0; i < status.refs.length; i++) { - var ref = status.refs[i]; - if(ref.type == "https://tent.io/types/photo/v0#") { - if(refs) { - for (var j = 0; j < refs.length; j++) { - var r = refs[j]; - if(ref.post == r.id) { - for (var k = 0; k < r.attachments.length; k++) { - var attachment = r.attachments[k]; - var a = document.createElement("a"); - var img = document.createElement("img"); - img.src = HostApp.serverUrl("attachment") - .replace(/\{entity\}/, encodeURIComponent(r.entity)) - .replace(/\{digest\}/, attachment.digest); - a.appendChild(img); - a.href = img.src; - template.images.appendChild(a); - } - } - } + if (status.type == "https://tent.io/types/post/photo/v0.1.0") { + + for (var i = 0; i < status.attachments.length; i++) { + // closure needed for the callback + (function() { + + var attachment = status.attachments[i]; + + var img = new Image(); + + img.className = "photo"; + template.images.appendChild(img); + + var callback = function(resp) { + img.src = "data:" + attachment.type + ";base64," + resp.responseText; } - } - } + + if (status.entity == HostApp.stringForKey("entity")) { + var url = Paths.mkApiRootPath("/posts/" + status.id + "/attachments/" + attachment.name); + Paths.getURL(url, "GET", callback, null, null, attachment.type); + } else { + var url = Paths.mkApiRootPath("/posts/" + encodeURIComponent(status.entity) + "/" + status.id + "/attachments/" + attachment.name); + Paths.getURL(url, "GET", callback, null, null, attachment.type); + } + })(); + } } this.findMentions(template.message, status.mentions); -/* for (var i = 0; i < status.mentions.length; i++) { var mention = status.mentions[i]; if (mention.entity == HostApp.stringForKey("entity")) { @@ -296,31 +327,27 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { break; } } -*/ - var published_at = typeof status.__repost == "undefined" ? status.version.published_at : status.__repost.published_at; + + var published_at = typeof status.__repost == "undefined" ? status.published_at : status.__repost.published_at; var time = document.createElement("abbr"); - time.innerText = this.ISODateString(new Date(published_at)); + time.innerText = this.ISODateString(new Date(published_at * 1000)); time.title = time.innerText; time.className = "timeago"; jQuery(time).timeago(); template.ago.appendChild(time); template.ago.href = "#" - - $(template.ago).single_double_click(function () { + template.ago.onclick = function() { HostApp.showConversation(status.id, status.entity); return false; - }, function () { - HostApp.showConversationViewForPostIdandEntity(status.id, status.entity); - return false; - }); + } - if (status.content && status.content.location) { - var lat = status.content.location.latitude; - var lng = status.content.location.longitude; - - if (typeof lat != "undefined" && typeof lng != "undefined") { + // {"type":"Point","coordinates":[57.10803113,12.25854746]} + if (status.content && status.content.location && (typeof status.content.location.type == "undefined" || status.content.location.type == "Point")) { + var lat = status.content.location.coordinates[0]; + var lng = status.content.location.coordinates[1]; + if (typeof lat != "undefined" && typeof lng != "undefined" && lat > 0 && lng > 0) { var href = this.mapHref(lat, lng); template.geo.href = href; template.geo.style.display = ""; @@ -335,20 +362,18 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { template.source.innerHTML = status.__repost.app.name; template.source.title = status.__repost.app.url; } else { - if(status.app) { - template.source.href = status.app.url; - template.source.innerHTML = status.app.name; - template.source.title = status.app.url; - } + template.source.href = status.app.url; + template.source.innerHTML = status.app.name; + template.source.title = status.app.url; } - return template.li; + return template.item; } - Core.prototype.getRepost = function(repost, before_node, append) { + Core.prototype.getRepost = function(repost, before_node) { - var post = document.getElementById("post-" + repost.refs[0].post + "-" + this.action); + var post = document.getElementById("post-" + repost.content.id); if (post) { @@ -386,7 +411,7 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { $(post).find(".reposted_by").show(); var li = $("
  • "); - li.attr("id", "post-" + repost.id + "-" + this.action) + li.attr("id", "post-" + repost.id) var a = $(""); a.attr("href", repost.entity); @@ -401,112 +426,100 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { return false; }); - var name = bungloo.cache.profiles[repost.entity] ? bungloo.cache.profiles[repost.entity].name : repost.entity; - a.html(name); + var _this = this; + Paths.findProfileURL(repost.entity, function(profile_url) { + if (profile_url) { + Paths.getURL(profile_url, "GET", function(resp) { + if (resp.status >= 200 && resp.status < 400) { + var _p = JSON.parse(resp.responseText); + _this.cache.profiles.setItem(repost.entity, _p); + + var basic = _p["https://tent.io/types/info/basic/v0.1.0"]; + if (basic && basic.name) { + a.html(basic.name); + } + + } + }, null, false); // do not send auth-headers + } + }); } else { - - var entity = repost.refs[0].entity ? repost.refs[0].entity : HostApp.stringForKey("entity"); - var id = repost.refs[0].post; - - var url = HostApp.serverUrl("post") - .replace(/\{entity\}/, encodeURIComponent(entity)) - .replace(/\{post\}/, id) - + "?profiles=entity"; - - var _this = this; - - APICalls.get(url, { callback: function(resp) { - - if (resp.status >= 200 && resp.status < 300 && before_node) { - var _statuses = JSON.parse(resp.responseText); - - for (var entity in _statuses.profiles) { - if (_statuses.profiles[entity] != null) { - bungloo.cache.profiles[entity] = _statuses.profiles[entity]; - } else { - bungloo.cache.profiles[entity] = {}; - } - } - - var status = _statuses.post; - - status.__repost = repost; - var li = _this.getStatusDOMElement(status); - if(!document.getElementById(li.id)) before_node.parentNode.insertBefore(li, before_node); - _this.getRepost(repost, before_node); // call this recursive because we now have the repost - } - - - }}); - - /* - var _this = this; var callback = function(resp) { if (resp.status >= 200 && resp.status < 300 && before_node) { var status = JSON.parse(resp.responseText); status.__repost = repost; var li = _this.getStatusDOMElement(status); - if(!document.getElementById(li.id)) before_node.parentNode.insertBefore(li, before_node); + before_node.parentNode.insertBefore(li, before_node); _this.getRepost(repost, before_node); // call this recursive because we now have the repost } } - APICalls.findProfileURL(repost.content.entity, function(profile_url) { + Paths.findProfileURL(repost.content.entity, function(profile_url) { if (profile_url) { - APICalls.http_call(profile_url, "GET", function(resp) { + Paths.getURL(profile_url, "GET", function(resp) { var profile = JSON.parse(resp.responseText); var server = profile["https://tent.io/types/info/core/v0.1.0"].servers[0]; - APICalls.http_call(URI(server + "/posts/" + repost.content.id).toString(), "GET", callback, null, false); + Paths.getURL(URI(server + "/posts/" + repost.content.id).toString(), "GET", callback, null, false); }, null, false); // do not send auth-headers } - });*/ + }); } } - Core.prototype.repost = function(status, callback) { - var type = status.type; - var id = status.id; - var entity = status.entity; - var url = HostApp.serverUrl("new_post"); - var data = { - type: "https://tent.io/types/repost/v0#" + type.split("#")[0], - refs: [ - { - post: id, - entity: entity - } - ], - mentions: [ - { - post: id, - type: type, - entity: entity - } + Core.prototype.sendNewMessage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, is_private, callback) { - ] - } + if (image_data_uri) { - APICalls.post(url, JSON.stringify(data), { - content_type: data.type, - accept: 'application/vnd.tent.post.v0+json; type="https://tent.io/types/repost/v0#"', - callback: function(resp) { - if (resp.status >= 200 < 300) { - controller.getNewData(); - if(callback) callback(resp); - } else { - debug(resp) + this.sendNewMessageWithImage(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, is_private, callback); + + } else { + + var url = URI(Paths.mkApiRootPath("/posts")); + + var http_method = "POST"; + + var data = { + "type": "https://tent.io/types/post/status/v0.1.0", + "published_at": parseInt(new Date().getTime() / 1000, 10), + "permissions": { + "public": !is_private + }, + "content": { + "text": content, + }, + }; + + if (location) { + data["content"]["location"] = { "type": "Point", "coordinates": location } + } + + var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity); + + if (mentions.length > 0) { + data["mentions"] = mentions; + if (is_private) { + var entities = {}; + for (var i = 0; i < mentions.length; i++) { + var entity = mentions[i]["entity"] + entities[entity] = true; + }; + + data["permissions"]["entities"] = entities; } } - }) + Paths.getURL(url.toString(), http_method, callback, JSON.stringify(data)); + } + } - /* - var url = URI(APICalls.mkApiRootPath("/posts")); + + Core.prototype.repost = function(id, entity, callback) { + var url = URI(Paths.mkApiRootPath("/posts")); var data = { "type": "https://tent.io/types/post/repost/v0.1.0", @@ -532,19 +545,88 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { _this.highlight(id); } - APICalls.http_call(url.toString(), "POST", new_callback, JSON.stringify(data));*/ + Paths.getURL(url.toString(), "POST", new_callback, JSON.stringify(data)); + } + + Core.prototype.sendNewMessageWithImage = function(content, in_reply_to_status_id, in_reply_to_entity, location, image_data_uri, is_private, callback) { + + var url = URI(Paths.mkApiRootPath("/posts")); + + var data = { + "type": "https://tent.io/types/post/photo/v0.1.0", + "published_at": parseInt(new Date().getTime() / 1000, 10), + "permissions": { + "public": !is_private + }, + "content": { + "caption": content, + }, + }; + + if (location) { + data["content"]["location"] = { "type": "Point", "coordinates": location } + } + + var mentions = this.parseMentions(content, in_reply_to_status_id, in_reply_to_entity); + if (mentions.length > 0) { + data["mentions"] = mentions; + if (is_private) { + var entities = {}; + for (var i = 0; i < mentions.length; i++) { + var entity = mentions[i]["entity"] + entities[entity] = true; + }; + + data["permissions"]["entities"] = entities; + } + } + + var data_string = JSON.stringify(data); + + var boundary = "TentAttachment----------TentAttachment"; + var post = "--" + boundary + "\r\n"; + + post += 'Content-Disposition: form-data; name="post"; filename="post.json"\r\n'; + post += 'Content-Length: ' + data_string.length + '\r\n'; + post += 'Content-Type: application/vnd.tent.v0+json\r\n'; + post += 'Content-Transfer-Encoding: binary\r\n\r\n'; + post += data_string; + + post += "\r\n--" + boundary + "\r\n"; + + var blob_string = image_data_uri.split(',')[1]; + var mime_type = image_data_uri.split(',')[0].split(':')[1].split(';')[0]; + var ext = "png"; + if (mime_type == "image/jpeg") { + ext = "jpeg"; + } else if (mime_type == "image/gif") { + ext = "gif"; + } + + + post += 'Content-Disposition: form-data; name="photos[0]"; filename="photo.' + ext + '"\r\n'; + post += 'Content-Length: ' + blob_string.length + "\r\n"; + post += 'Content-Type: ' + mime_type + "\r\n"; + post += 'Content-Transfer-Encoding: base64\r\n\r\n'; + post += blob_string; + post += "\r\n--" + boundary + "--\r\n"; + + var newCallback = function(resp) { + if (resp.status == 403) { + var err = JSON.parse(resp.responseText); + HostApp.alertTitleWithMessage(resp.statusText, err.error); + } + callback(resp); + } + + Paths.postMultipart(url.toString(), newCallback, post, boundary); } Core.prototype.remove = function(id, callback, type) { type = type || "post"; if (confirm("Really delete this " + type + "?")) { - - var entity = HostApp.stringForKey("entity"); - var url = HostApp.serverUrl("post") - .replace(/\{entity\}/, encodeURIComponent(entity)) - .replace(/\{post\}/, id); - - APICalls.delete(url, { callback: callback }); + var url = URI(Paths.mkApiRootPath("/posts/" + id)); + Paths.getURL(url.toString(), "DELETE", callback); } } @@ -596,15 +678,13 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { if (e.substring(0,7) != "http://" && e.substring(0,8) != "https://") { e = "https://" + e; } - if(mentions) { - for (var j = 0; j < mentions.length; j++) { - var m = mentions[j]; - if(m && m.entity && m.entity.startsWith(e)) { - mentions_in_text.push({ - entity: m.entity, - text: name - }); - } + for (var j = 0; j < mentions.length; j++) { + var m = mentions[j]; + if(m.entity.startsWith(e)) { + mentions_in_text.push({ + entity: m.entity, + text: name + }); } } } @@ -633,8 +713,12 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { + "" ); + // adding show profile on click node.innerHTML = new_text; - _this.afterChangingTextinMessageHTML(node); + $(node).find("a.name").click(function(e) { + HostApp.showProfileForEntity(e.target.title); + return false; + }); // adding comma between names when there is only // a space in between. @@ -647,17 +731,25 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { } } - APICalls.findProfileURL(mention.entity, function(profile_url) { - if (profile_url) { - APICalls.http_call(profile_url, "GET", function(resp) { - if (resp.status >= 200 && resp.status < 400) { - var p = JSON.parse(resp.responseText); - _this.cache.profiles.setItem(mention.entity, p); - profile(p) - } - }, null, false); // do not send auth-headers - } - }); + var p = _this.cache.profiles.getItem(mention.entity); + if (p) { + + profile(p); + + } else { + + Paths.findProfileURL(mention.entity, function(profile_url) { + if (profile_url) { + Paths.getURL(profile_url, "GET", function(resp) { + if (resp.status >= 200 && resp.status < 400) { + var p = JSON.parse(resp.responseText); + _this.cache.profiles.setItem(mention.entity, p); + profile(p) + } + }, null, false); // do not send auth-headers + } + }); + } })(mention); } @@ -704,8 +796,27 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { } Core.prototype.replaceURLWithHTMLLinks = function(text, entities, message_node) { - return Markdown.toHTML( text, 'Tent', { footnotes: entities } ) - .replace(/\^' + url + ''; + } + } + + return result; + } + + var hash = /(^|\s)(#)(\w+)/ig; + + return URI.withinString(text, callback).replace(hash, "$1$2$3"); } Core.prototype.parseForMedia = function(text, images) { @@ -727,7 +838,7 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { } else if(word.startsWith("http://youtube.com/") || word.startsWith("http://www.youtube.com/") || word.startsWith("https://youtube.com/") || word.startsWith("https://www.youtube.com/")) { - var v = APICalls.getUrlVars(word)["v"]; + var v = Paths.getUrlVars(word)["v"]; this.addYouTube(v, images); } else if (word.startsWith("http://youtu.be/") || word.startsWith("https://youtu.be/")) { @@ -779,12 +890,23 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { } } - Core.prototype.replyTo = function(status) { - HostApp.openNewMessageWidow(status); + Core.prototype.replyTo = function(entity, status_id, mentions, is_private) { + + var string = "^" + entity.replace("https://", "") + " "; + + var ms = ""; + for (var i = 0; i < mentions.length; i++) { + var e = mentions[i].entity.replace("https://", ""); + if(string.indexOf(e) == -1) ms += " ^" + e; + } + + if(ms.length > 0) string += "\n\n/cc" + ms; + + HostApp.openNewMessageWidow(entity, status_id, string, is_private); } Core.prototype.postDeleted = function(post_id, entity) { - var li = document.getElementById("post-" + post_id + "-" + this.action); + var li = document.getElementById("post-" + post_id); if (li) { if (li.parentNode == this.body) { this.body.removeChild(li); @@ -819,25 +941,22 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { } Core.prototype.mapHref = function(lat, lng) { - return "http://www.openstreetmap.org/?mlat=" + lat.toString() + "&mlon=" + lng.toString() + "&zoom=12"; + return "http://www.openstreetmap.org/?mlat=" + lat + "&mlon=" + lng + "&zoom=12"; } Core.prototype.mapSrc = function(lat, lng) { - var width = $("div:visible div.message").width(); - return "http://staticmap.openstreetmap.de/staticmap.php?center=" + lat.toString() + "," + lng.toString() + "&zoom=3&size=" + width + "x75&markers=" + lat + "," + lng + ",red-pushpin"; + var width = $("p.message").width(); + return "http://staticmap.openstreetmap.de/staticmap.php?center=" + lat + "," + lng + "&zoom=3&size=" + width + "x75&markers=" + lat + "," + lng + ",red-pushpin"; } Core.prototype.addMap = function(lat, lng, images) { - var self = this; - setTimeout(function(){ - var a = document.createElement("a"); - a.className = "map"; - a.href = self.mapHref(lat, lng); - var img = document.createElement("img"); - img.src = self.mapSrc(lat, lng); - a.appendChild(img); - images.appendChild(a); - }, 200); + var a = document.createElement("a"); + a.className = "map"; + a.href = this.mapHref(lat, lng); + var img = document.createElement("img"); + img.src = this.mapSrc(lat, lng); + a.appendChild(img); + images.appendChild(a); } Core.prototype.addYouTube = function(id, images) { @@ -877,22 +996,6 @@ function(jQuery, APICalls, URI, HostApp, Markdown) { $(images).append(''); } - Core.prototype.afterChangingTextinMessageHTML = function(message_node) { - // adding show search on click hash - /* - $(message_node).find("a.hash").click(function(e) { - - if(bungloo.search) bungloo.search.searchFor(e.target.innerHTML); - return false; - }); - */ - // adding show profile on click - /* - $(message_node).find("a.name").click(function(e) { - HostApp.showProfileForEntity(e.target.title); - return false; - });*/ - } return Core; diff --git a/WebKit/scripts/helper/Hmac.js b/WebKit/scripts/helper/Hmac.js index be4db38..b22a2f3 100644 --- a/WebKit/scripts/helper/Hmac.js +++ b/WebKit/scripts/helper/Hmac.js @@ -7,7 +7,7 @@ function(URI, CryptoJS) { var Hmac = {}; - Hmac.makeHawkAuthHeader = function(url, http_method, hawk_id, key, app_id) { + Hmac.makeAuthHeader = function(url, http_method, mac_key, mac_key_id) { url = URI(url); var nonce = Hmac.makeid(8); @@ -18,47 +18,26 @@ function(URI, CryptoJS) { port = url.protocol() == "https" ? "443" : "80"; } - var normalizedRequestString = "hawk.1.header\n" // header - + time_stamp + '\n' // ts - + nonce + '\n' // nonce - + http_method.toUpperCase() + '\n' // method - + url.path() + url.search() + url.hash() + '\n' // request uri - + url.hostname().toLowerCase() + '\n' // host - + port + '\n' // port - + '\n' // Hmac.calculatePayloadHash(payload) + '\n' // hash // FIXME implement payload validation - + '\n' // ext (we don't use it) + var normalizedRequestString = "" + + time_stamp + '\n' + + nonce + '\n' + + http_method + '\n' + + url.path() + url.search() + url.hash() + '\n' + + url.hostname() + '\n' + + port + '\n' + + '\n' ; - var app = ""; - - if(app_id) { - app = ', app="' + app_id + "'"; - normalizedRequestString += app_id + "\n" + // app - '\n'; // dlg should be empty - } - - var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, key); + var hmac = CryptoJS.algo.HMAC.create(CryptoJS.algo.SHA256, mac_key); hmac.update(normalizedRequestString); var hash = hmac.finalize(); var mac = hash.toString(CryptoJS.enc.Base64); - return 'Hawk id="' + hawk_id + - '", mac="' + mac + + return 'MAC id="' + mac_key_id + '", ts="' + time_stamp + - '", nonce="' + nonce + '"' + - app + '", nonce="' + nonce + + '", mac="' + mac + '"'; } - Hmac.calculatePayloadHash = function (payload) { - if (!payload) return ""; - - var hash = CryptoJS.algo.SHA256.create(); - hash.update('hawk.1.payload\n'); - hash.update('application/vnd.tent.post.v0+json\n'); - hash.update(payload || ''); - hash.update('\n'); - return hash.finalize().toString(CryptoJS.enc.Base64); - }, - Hmac.makeid = function(len) { var text = ""; var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; diff --git a/WebKit/scripts/helper/HostApp.js b/WebKit/scripts/helper/HostApp.js index 9811fda..50bcbe8 100644 --- a/WebKit/scripts/helper/HostApp.js +++ b/WebKit/scripts/helper/HostApp.js @@ -37,14 +37,6 @@ define(function() { } } - HostApp.setServerUrls = function(server_urls) { - HostApp.setStringForKey(JSON.stringify(server_urls), "server_urls"); - } - - HostApp.serverUrl = function(key) { - return JSON.parse(HostApp.stringForKey("server_urls"))[key]; - } - HostApp.openURL = function(url) { if (OS_TYPE == "mac") { @@ -85,12 +77,12 @@ define(function() { } } - HostApp.openNewMessageWidow = function(status) { + HostApp.openNewMessageWidow = function(entity, status_id, string, is_private) { if (OS_TYPE == "mac") { - controller.openNewMessageWindowInReplyToStatus_(JSON.stringify(status)); + controller.openNewMessageWindowInReplyTo_statusId_withString_isPrivate_(entity, status_id, string, is_private); } else { - controller.openNewMessageWindowInReplyToStatus(JSON.stringify(status).escapeSpecialChars()); + controller.openNewMessageWindowInReplyTostatusIdwithStringIsPrivate(entity, status_id, string, is_private); } } @@ -103,14 +95,6 @@ define(function() { } } - HostApp.showConversationViewForPostIdandEntity = function(id, entity) { - if (OS_TYPE == "mac") { - controller.showConversationViewForPostId_andEntity_(id, entity); - } else { - controller.showConversationViewForPostIdandEntity(id, entity); - } - } - HostApp.showProfileForEntity = function(entity) { if (OS_TYPE == "mac") { @@ -145,10 +129,7 @@ define(function() { } HostApp.osType = function() { - var os_name = "OS X"; - if (OS_TYPE == "windows") os_name = "Windows"; - if (OS_TYPE == "linux") os_name = "Linux" - return os_name; + return OS_TYPE == "mac" ? "OS X" : "Linux"; } HostApp.notificateViewsAboutDeletedPost = function(postId, entity) { diff --git a/WebKit/scripts/helper/Paths.js b/WebKit/scripts/helper/Paths.js index af1fb75..5f477a7 100644 --- a/WebKit/scripts/helper/Paths.js +++ b/WebKit/scripts/helper/Paths.js @@ -25,7 +25,7 @@ function(jQuery, HostApp, Hmac, Cache) { Paths.getURL = function(url, http_method, callback, data, auth_header, accepts) { - if(accepts !== false) accepts = accepts || "application/vnd.tent.post.v0+json"; + if(accepts !== false) accepts = accepts || "application/vnd.tent.v0+json; charset=utf-8"; var options = { @@ -56,7 +56,7 @@ function(jQuery, HostApp, Hmac, Cache) { } }, url: url, - contentType: 'application/vnd.tent.post.v0+json; type="https://tent.io/types/app/v0#"', + contentType: "application/vnd.tent.v0+json", type: http_method, complete: callback, data: data, @@ -65,7 +65,7 @@ function(jQuery, HostApp, Hmac, Cache) { console.error("getURL (" + xhr.status + ")" + xhr.statusText + " " + http_method + " (" + url + "): '" + xhr.responseText + "'"); } } - + jQuery.ajax(options); } @@ -127,7 +127,7 @@ function(jQuery, HostApp, Hmac, Cache) { if(profile_urls.length > 0) { var profile_url = profile_urls[0]; if (!profile_url.startsWith("http")) { - profile_url = entity + profile_url; + profile_url = entity + "/profile"; } } @@ -140,13 +140,13 @@ function(jQuery, HostApp, Hmac, Cache) { if (resp.status >= 200 && resp.status < 300) { var doc = document.implementation.createHTMLDocument(""); doc.documentElement.innerHTML = resp.responseText; - var links = $(doc).find("link[rel='https://tent.io/rels/meta-post']"); + var links = $(doc).find("link[rel='https://tent.io/rels/profile']"); if (links.length > 0) { var href = links.get(0).href; Paths.cache.profile_urls.setItem(entity, href); if (!href.startsWith("http")) { - href = entity + href; + href = entity + "/profile"; } callback(href); @@ -184,11 +184,6 @@ function(jQuery, HostApp, Hmac, Cache) { } Paths.parseHeaderForProfiles = function(header_string) { - var regexp = /https:\/\/tent.io\/rels\/meta-post/i; - return Paths.parseHeaderForLink(header_string, regexp); - } - - Paths.parseHeaderForLink = function(header_string, match) { var headers = header_string.split(/\n/); var links = []; for (var i = 0; i < headers.length; i++) { @@ -202,18 +197,18 @@ function(jQuery, HostApp, Hmac, Cache) { for (var i = 0; i < links.length; i++) { items = items.concat(links[i].split(",")); } - var things = []; + var profiles = []; for (var i = 0; i < items.length; i++) { var item = items[i]; - if (item.match(match)) { + if (item.match(/https:\/\/tent.io\/rels\/profile/i)) { var n = item.match(/<([^>]*)>/); if (n) { - things.push(n[1]); + profiles.push(n[1]); } } } - return things; + return profiles; } return Paths; diff --git a/WebKit/scripts/lib/Markdown.js b/WebKit/scripts/lib/Markdown.js deleted file mode 100644 index bbe9077..0000000 --- a/WebKit/scripts/lib/Markdown.js +++ /dev/null @@ -1,7 +0,0 @@ -define([ - "lib/vendor/tent-markdown" -], - -function() { - return window.markdown; -}); \ No newline at end of file diff --git a/WebKit/scripts/lib/SingleDoubleClick.js b/WebKit/scripts/lib/SingleDoubleClick.js deleted file mode 100644 index 70c248f..0000000 --- a/WebKit/scripts/lib/SingleDoubleClick.js +++ /dev/null @@ -1,31 +0,0 @@ -define([ - "jquery" -], - -function(jQuery) { - -// Author: Jacek Becela -// Source: http://gist.github.com/399624 -// License: MIT - -jQuery.fn.single_double_click = function(single_click_callback, double_click_callback, timeout) { - return this.each(function(){ - var clicks = 0, self = this; - jQuery(this).click(function(event){ - clicks++; - if (clicks == 1) { - setTimeout(function(){ - if(clicks == 1) { - single_click_callback.call(self, event); - } else { - double_click_callback.call(self, event); - } - clicks = 0; - }, timeout || 300); - } - return false; // added by jeena so it doesn't follow links - }); - }); -} - -}) \ No newline at end of file diff --git a/WebKit/scripts/lib/vendor/tent-markdown.js b/WebKit/scripts/lib/vendor/tent-markdown.js deleted file mode 100644 index 34013e2..0000000 --- a/WebKit/scripts/lib/vendor/tent-markdown.js +++ /dev/null @@ -1,1219 +0,0 @@ -/* - Adapted from https://github.com/twitter/twitter-text-js - - Copyright 2011 Twitter, Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this work except in compliance with the License. - You may obtain a copy of the License below, or at: - - http://www.apache.org/licenses/LICENSE-2.0 -*/ - -(function(expose) { - - twttr = { txt: { regexen: {} } } - - // Builds a RegExp - function regexSupplant(regex, flags) { - flags = flags || ""; - if (typeof regex !== "string") { - if (regex.global && flags.indexOf("g") < 0) { - flags += "g"; - } - if (regex.ignoreCase && flags.indexOf("i") < 0) { - flags += "i"; - } - if (regex.multiline && flags.indexOf("m") < 0) { - flags += "m"; - } - - regex = regex.source; - } - - return new RegExp(regex.replace(/#\{(\w+)\}/g, function(match, name) { - var newRegex = twttr.txt.regexen[name] || ""; - if (typeof newRegex !== "string") { - newRegex = newRegex.source; - } - return newRegex; - }), flags); - } - - twttr.txt.regexSupplant = regexSupplant; - - // simple string interpolation - function stringSupplant(str, values) { - return str.replace(/#\{(\w+)\}/g, function(match, name) { - return values[name] || ""; - }); - } - - var fromCode = String.fromCharCode; - var INVALID_CHARS = [ - fromCode(0xFFFE), - fromCode(0xFEFF), // BOM - fromCode(0xFFFF) // Special - ]; - - twttr.txt.regexen.invalid_chars_group = regexSupplant(INVALID_CHARS.join("")); - - twttr.txt.stringSupplant = stringSupplant; - - twttr.txt.stringSupplant = stringSupplant - - var UNICODE_SPACES = [ - fromCode(0x0020), // White_Space # Zs SPACE - fromCode(0x0085), // White_Space # Cc - fromCode(0x00A0), // White_Space # Zs NO-BREAK SPACE - fromCode(0x1680), // White_Space # Zs OGHAM SPACE MARK - fromCode(0x180E), // White_Space # Zs MONGOLIAN VOWEL SEPARATOR - fromCode(0x2028), // White_Space # Zl LINE SEPARATOR - fromCode(0x2029), // White_Space # Zp PARAGRAPH SEPARATOR - fromCode(0x202F), // White_Space # Zs NARROW NO-BREAK SPACE - fromCode(0x205F), // White_Space # Zs MEDIUM MATHEMATICAL SPACE - fromCode(0x3000) // White_Space # Zs IDEOGRAPHIC SPACE - ]; - - twttr.txt.regexen.spaces_group = regexSupplant(UNICODE_SPACES.join("")); - twttr.txt.regexen.spaces = regexSupplant("[" + UNICODE_SPACES.join("") + "]"); - twttr.txt.regexen.invalid_chars_group = regexSupplant(INVALID_CHARS.join("")); - twttr.txt.regexen.punct = /\!'#%&'\(\)*\+,\\\-\.\/:;<=>\?@\[\]\^_{|}~\$/; - - // URL related regex collection - twttr.txt.regexen.validUrlPrecedingChars = regexSupplant(/(?:[^A-Za-z0-9@@$###{invalid_chars_group}]|^)/); - twttr.txt.regexen.invalidUrlWithoutProtocolPrecedingChars = /[-_.\/]$/; - twttr.txt.regexen.invalidDomainChars = stringSupplant("#{punct}#{spaces_group}#{invalid_chars_group}", twttr.txt.regexen); - twttr.txt.regexen.validDomainChars = regexSupplant(/[^#{invalidDomainChars}]/); - twttr.txt.regexen.validSubdomain = regexSupplant(/(?:(?:#{validDomainChars}(?:[_-]|#{validDomainChars})*)?#{validDomainChars}\.)/); - twttr.txt.regexen.validDomainName = regexSupplant(/(?:(?:#{validDomainChars}(?:-|#{validDomainChars})*)?#{validDomainChars}\.)/); - twttr.txt.regexen.validGTLD = regexSupplant(/(?:(?:aero|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|xxx|local)(?=[^0-9a-zA-Z]|$))/); - twttr.txt.regexen.validCCTLD = regexSupplant(/(?:(?:ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cs|cu|cv|cx|cy|cz|dd|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mm|mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ro|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|ss|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|za|zm|zw)(?=[^0-9a-zA-Z]|$))/); - twttr.txt.regexen.validPunycode = regexSupplant(/(?:xn--[0-9a-z]+)/); - twttr.txt.regexen.validDomain = regexSupplant(/(?:#{validSubdomain}*#{validDomainName}(?:#{validGTLD}|#{validCCTLD}|#{validPunycode}))/); - twttr.txt.regexen.validAsciiDomain = regexSupplant(/(?:(?:[-a-z0-9#{latinAccentChars}]+)\.)+(?:#{validGTLD}|#{validCCTLD}|#{validPunycode})/gi); - twttr.txt.regexen.invalidShortDomain = regexSupplant(/^#{validDomainName}#{validCCTLD}$/); - - twttr.txt.regexen.validPortNumber = regexSupplant(/[0-9]+/); - - twttr.txt.regexen.validGeneralUrlPathChars = regexSupplant(/[a-z0-9!\*';:=\+,\.\$\/%#\[\]\-_~|&#{latinAccentChars}]/i); - // Allow URL paths to contain balanced parens - // 1. Used in Wikipedia URLs like /Primer_(film) - // 2. Used in IIS sessions like /S(dfd346)/ - twttr.txt.regexen.validUrlBalancedParens = regexSupplant(/\(#{validGeneralUrlPathChars}+\)/i); - // Valid end-of-path chracters (so /foo. does not gobble the period). - // 1. Allow =&# for empty URL parameters and other URL-join artifacts - twttr.txt.regexen.validUrlPathEndingChars = regexSupplant(/[\+\-a-z0-9=_#\/#{latinAccentChars}]|(?:#{validUrlBalancedParens})/i); - // Allow @ in a url, but only in the middle. Catch things like http://example.com/@user/ - twttr.txt.regexen.validUrlPath = regexSupplant('(?:' + - '(?:' + - '#{validGeneralUrlPathChars}*' + - '(?:#{validUrlBalancedParens}#{validGeneralUrlPathChars}*)*' + - '#{validUrlPathEndingChars}'+ - ')|(?:@#{validGeneralUrlPathChars}+\/)'+ - ')', 'i'); - - twttr.txt.regexen.validUrlQueryChars = /[a-z0-9!?\*'\(\);:&=\+\$\/%#\[\]\-_\.,~|]/i; - twttr.txt.regexen.validUrlQueryEndingChars = /[a-z0-9_&=#\/]/i; - twttr.txt.regexen.extractUrl = regexSupplant( - '(' + // $1 total match - '(#{validUrlPrecedingChars})' + // $2 Preceeding chracter - '(' + // $3 URL - '(https?:\\/\\/)?' + // $4 Protocol (optional) - '(#{validDomain})' + // $5 Domain(s) - '(?::(#{validPortNumber}))?' + // $6 Port number (optional) - '(\\/#{validUrlPath}*)?' + // $7 URL Path - '(\\?#{validUrlQueryChars}*#{validUrlQueryEndingChars})?' + // $8 Query String - ')' + - ')' - , 'gi'); - - twttr.txt.regexen.validTcoUrl = /^https?:\/\/t\.co\/[a-z0-9]+/i; - - twttr.extractUrlsWithIndices = function(text, options) { - if (!options) { - options = {extractUrlsWithoutProtocol: true}; - } - - if (!text || (options.extractUrlsWithoutProtocol ? !text.match(/\./) : !text.match(/:/))) { - return []; - } - - var urls = []; - - while (twttr.txt.regexen.extractUrl.exec(text)) { - var before = RegExp.$2, url = RegExp.$3, protocol = RegExp.$4, domain = RegExp.$5, path = RegExp.$7; - var endPosition = twttr.txt.regexen.extractUrl.lastIndex, - startPosition = endPosition - url.length; - - // if protocol is missing and domain contains non-ASCII characters, - // extract ASCII-only domains. - if (!protocol) { - if (!options.extractUrlsWithoutProtocol - || before.match(twttr.txt.regexen.invalidUrlWithoutProtocolPrecedingChars)) { - continue; - } - var lastUrl = null, - lastUrlInvalidMatch = false, - asciiEndPosition = 0; - domain.replace(twttr.txt.regexen.validAsciiDomain, function(asciiDomain) { - var asciiStartPosition = domain.indexOf(asciiDomain, asciiEndPosition); - asciiEndPosition = asciiStartPosition + asciiDomain.length; - lastUrl = { - url: asciiDomain, - indices: [startPosition + asciiStartPosition, startPosition + asciiEndPosition] - }; - if (!before.match(/^[\^]$/)) { - lastUrlInvalidMatch = asciiDomain.match(twttr.txt.regexen.invalidShortDomain); - } - if (!lastUrlInvalidMatch) { - urls.push(lastUrl); - } - }); - - // no ASCII-only domain found. Skip the entire URL. - if (lastUrl == null) { - continue; - } - - // lastUrl only contains domain. Need to add path and query if they exist. - if (path) { - if (lastUrlInvalidMatch) { - urls.push(lastUrl); - } - lastUrl.url = url.replace(domain, lastUrl.url); - lastUrl.indices[1] = endPosition; - } - } else { - // In the case of t.co URLs, don't allow additional path characters. - if (url.match(twttr.txt.regexen.validTcoUrl)) { - url = RegExp.lastMatch; - endPosition = startPosition + url.length; - } - urls.push({ - url: url, - indices: [startPosition, endPosition] - }); - } - } - - return urls; - }; - - expose.extractUrlsWithIndices = twttr.extractUrlsWithIndices; - -})((function() { - if (typeof exports === "undefined") { - window.twttr = {}; - return window.twttr; - } else { - return exports; - } -})()); -// Released under MIT license -// Copyright (c) 2009-2010 Dominic Baggott -// Copyright (c) 2009-2010 Ash Berlin -// Copyright (c) 2011 Christoph Dorn (http://www.christophdorn.com) - -/*jshint browser:true, devel:true */ - -(function( expose ) { - -var Markdown = expose.Markdown = function(dialect) { - switch (typeof dialect) { - case "undefined": - this.dialect = Markdown.dialects.Gruber; - break; - case "object": - this.dialect = dialect; - break; - default: - if ( dialect in Markdown.dialects ) { - this.dialect = Markdown.dialects[dialect]; - } - else { - throw new Error("Unknown Markdown dialect '" + String(dialect) + "'"); - } - break; - } - this.em_state = []; - this.strong_state = []; - this.debug_indent = ""; -}; - -/** - * parse( markdown, [dialect] ) -> JsonML - * - markdown (String): markdown string to parse - * - dialect (String | Dialect): the dialect to use, defaults to gruber - * - * Parse `markdown` and return a markdown document as a Markdown.JsonML tree. - **/ -expose.parse = function( source, dialect ) { - // dialect will default if undefined - var md = new Markdown( dialect ); - return md.toTree( source ); -}; - -/** - * toHTML( markdown, [dialect] ) -> String - * toHTML( md_tree ) -> String - * - markdown (String): markdown string to parse - * - md_tree (Markdown.JsonML): parsed markdown tree - * - * Take markdown (either as a string or as a JsonML tree) and run it through - * [[toHTMLTree]] then turn it into a well-formated HTML fragment. - **/ -expose.toHTML = function toHTML( source , dialect , options ) { - var input = expose.toHTMLTree( source , dialect , options ); - - return expose.renderJsonML( input ); -}; - -/** - * toHTMLTree( markdown, [dialect] ) -> JsonML - * toHTMLTree( md_tree ) -> JsonML - * - markdown (String): markdown string to parse - * - dialect (String | Dialect): the dialect to use, defaults to gruber - * - md_tree (Markdown.JsonML): parsed markdown tree - * - * Turn markdown into HTML, represented as a JsonML tree. If a string is given - * to this function, it is first parsed into a markdown tree by calling - * [[parse]]. - **/ -expose.toHTMLTree = function toHTMLTree( input, dialect , options ) { - // convert string input to an MD tree - if ( typeof input ==="string" ) input = this.parse( input, dialect ); - - // Now convert the MD tree to an HTML tree - - // remove references from the tree - var attrs = extract_attr( input ), - refs = {}; - - if ( attrs && attrs.references ) { - refs = attrs.references; - } - - var html = convert_tree_to_html( input, refs , options ); - merge_text_nodes( html ); - return html; -}; - -// For Spidermonkey based engines -function mk_block_toSource() { - return "Markdown.mk_block( " + - uneval(this.toString()) + - ", " + - uneval(this.trailing) + - ", " + - uneval(this.lineNumber) + - " )"; -} - -// node -function mk_block_inspect() { - var util = require("util"); - return "Markdown.mk_block( " + - util.inspect(this.toString()) + - ", " + - util.inspect(this.trailing) + - ", " + - util.inspect(this.lineNumber) + - " )"; - -} - -var mk_block = Markdown.mk_block = function(block, trail, line) { - // Be helpful for default case in tests. - if ( arguments.length == 1 ) trail = "\n\n"; - - var s = new String(block); - s.trailing = trail; - // To make it clear its not just a string - s.inspect = mk_block_inspect; - s.toSource = mk_block_toSource; - - if ( line != undefined ) - s.lineNumber = line; - - return s; -}; - -function count_lines( str ) { - var n = 0, i = -1; - while ( ( i = str.indexOf("\n", i + 1) ) !== -1 ) n++; - return n; -} - -// Internal - split source into rough blocks -Markdown.prototype.split_blocks = function splitBlocks( input, startLine ) { - input = input.replace(/(\r\n|\n|\r)/g, "\n"); - // [\s\S] matches _anything_ (newline or space) - var re = /([\s\S]+?)($|\n(?:\s*\n|$)+)/g, - blocks = [], - m; - - var line_no = 1; - - if ( ( m = /^(\s*\n)/.exec(input) ) != null ) { - // skip (but count) leading blank lines - line_no += count_lines( m[0] ); - re.lastIndex = m[0].length; - } - - while ( ( m = re.exec(input) ) !== null ) { - blocks.push( mk_block( m[1], m[2], line_no ) ); - line_no += count_lines( m[0] ); - } - - return blocks; -}; - -/** - * Markdown#processBlock( block, next ) -> undefined | [ JsonML, ... ] - * - block (String): the block to process - * - next (Array): the following blocks - * - * Process `block` and return an array of JsonML nodes representing `block`. - * - * It does this by asking each block level function in the dialect to process - * the block until one can. Succesful handling is indicated by returning an - * array (with zero or more JsonML nodes), failure by a false value. - * - * Blocks handlers are responsible for calling [[Markdown#processInline]] - * themselves as appropriate. - * - * If the blocks were split incorrectly or adjacent blocks need collapsing you - * can adjust `next` in place using shift/splice etc. - * - * If any of this default behaviour is not right for the dialect, you can - * define a `__call__` method on the dialect that will get invoked to handle - * the block processing. - */ -Markdown.prototype.processBlock = function processBlock( block, next ) { - var cbs = this.dialect.block, - ord = cbs.__order__; - - if ( "__call__" in cbs ) { - return cbs.__call__.call(this, block, next); - } - - for ( var i = 0; i < ord.length; i++ ) { - //D:this.debug( "Testing", ord[i] ); - var res = cbs[ ord[i] ].call( this, block, next ); - if ( res ) { - //D:this.debug(" matched"); - if ( !isArray(res) || ( res.length > 0 && !( isArray(res[0]) ) ) ) - this.debug(ord[i], "didn't return a proper array"); - //D:this.debug( "" ); - return res; - } - } - - // Uhoh! no match! Should we throw an error? - return []; -}; - -Markdown.prototype.processInline = function processInline( block ) { - return this.dialect.inline.__call__.call( this, String( block ) ); -}; - -/** - * Markdown#toTree( source ) -> JsonML - * - source (String): markdown source to parse - * - * Parse `source` into a JsonML tree representing the markdown document. - **/ -// custom_tree means set this.tree to `custom_tree` and restore old value on return -Markdown.prototype.toTree = function toTree( source, custom_root ) { - var blocks = source instanceof Array ? source : this.split_blocks( source ); - - // Make tree a member variable so its easier to mess with in extensions - var old_tree = this.tree; - try { - this.tree = custom_root || this.tree || [ "markdown" ]; - - blocks: - while ( blocks.length ) { - var b = this.processBlock( blocks.shift(), blocks ); - - // Reference blocks and the like won't return any content - if ( !b.length ) continue blocks; - - this.tree.push.apply( this.tree, b ); - } - return this.tree; - } - finally { - if ( custom_root ) { - this.tree = old_tree; - } - } -}; - -// Noop by default -Markdown.prototype.debug = function () { - var args = Array.prototype.slice.call( arguments); - args.unshift(this.debug_indent); - if ( typeof print !== "undefined" ) - print.apply( print, args ); - if ( typeof console !== "undefined" && typeof console.log !== "undefined" ) - console.log.apply( null, args ); -} - -Markdown.prototype.loop_re_over_block = function( re, block, cb ) { - // Dont use /g regexps with this - var m, - b = block.valueOf(); - - while ( b.length && (m = re.exec(b) ) != null ) { - b = b.substr( m[0].length ); - cb.call(this, m); - } - return b; -}; - -/** - * Markdown.dialects - * - * Namespace of built-in dialects. - **/ -Markdown.dialects = {}; - -// Build default order from insertion order. -Markdown.buildBlockOrder = function(d) { - var ord = []; - for ( var i in d ) { - if ( i == "__order__" || i == "__call__" ) continue; - ord.push( i ); - } - d.__order__ = ord; -}; - -// Build patterns for inline matcher -Markdown.buildInlinePatterns = function(d) { - var patterns = []; - - for ( var i in d ) { - // __foo__ is reserved and not a pattern - if ( i.match( /^__.*__$/) ) continue; - var l = i.replace( /([\\.*+?|()\[\]{}])/g, "\\$1" ) - .replace( /\n/, "\\n" ); - patterns.push( i.length == 1 ? l : "(?:" + l + ")" ); - } - - patterns = patterns.join("|"); - d.__patterns__ = patterns; - //print("patterns:", uneval( patterns ) ); - - var fn = d.__call__; - d.__call__ = function(text, pattern) { - if ( pattern != undefined ) { - return fn.call(this, text, pattern); - } - else - { - return fn.call(this, text, patterns); - } - }; -}; - -Markdown.DialectHelpers = {}; -Markdown.DialectHelpers.inline_until_char = function( text, want ) { - var consumed = 0, - nodes = []; - - while ( true ) { - if ( text.charAt( consumed ) == want ) { - // Found the character we were looking for - consumed++; - return [ consumed, nodes ]; - } - - if ( consumed >= text.length ) { - // No closing char found. Abort. - return null; - } - - var res = this.dialect.inline.__oneElement__.call(this, text.substr( consumed ) ); - consumed += res[ 0 ]; - // Add any returned nodes. - nodes.push.apply( nodes, res.slice( 1 ) ); - } -} - -var isArray = Array.isArray || function(obj) { - return Object.prototype.toString.call(obj) == "[object Array]"; -}; - -function extract_attr( jsonml ) { - return isArray(jsonml) - && jsonml.length > 1 - && typeof jsonml[ 1 ] === "object" - && !( isArray(jsonml[ 1 ]) ) - ? jsonml[ 1 ] - : undefined; -} - - - -/** - * renderJsonML( jsonml[, options] ) -> String - * - jsonml (Array): JsonML array to render to XML - * - options (Object): options - * - * Converts the given JsonML into well-formed XML. - * - * The options currently understood are: - * - * - root (Boolean): wether or not the root node should be included in the - * output, or just its children. The default `false` is to not include the - * root itself. - */ -expose.renderJsonML = function( jsonml, options ) { - options = options || {}; - // include the root element in the rendered output? - options.root = options.root || false; - - var content = []; - - if ( options.root ) { - content.push( render_tree( jsonml ) ); - } - else { - jsonml.shift(); // get rid of the tag - if ( jsonml.length && typeof jsonml[ 0 ] === "object" && !( jsonml[ 0 ] instanceof Array ) ) { - jsonml.shift(); // get rid of the attributes - } - - while ( jsonml.length ) { - content.push( render_tree( jsonml.shift() ) ); - } - } - - return content.join( "\n\n" ); -}; - -function escapeHTML( text ) { - return text.replace( /&/g, "&" ) - .replace( //g, ">" ) - .replace( /"/g, """ ) - .replace( /'/g, "'" ); -} - -function render_tree( jsonml ) { - // basic case - if ( typeof jsonml === "string" ) { - return escapeHTML( jsonml ); - } - - var tag = jsonml.shift(), - attributes = {}, - content = []; - - if ( jsonml.length && typeof jsonml[ 0 ] === "object" && !( jsonml[ 0 ] instanceof Array ) ) { - attributes = jsonml.shift(); - } - - while ( jsonml.length ) { - content.push( render_tree( jsonml.shift() ) ); - } - - // edge case where tag has been removed at some point (e.g. preprocessTreeNode) - if ( !tag ) { - return content - } - - var tag_attrs = ""; - for ( var a in attributes ) { - tag_attrs += " " + a + '="' + escapeHTML( attributes[ a ] ) + '"'; - } - - // be careful about adding whitespace here for inline elements - if ( tag == "img" || tag == "br" || tag == "hr" ) { - return "<"+ tag + tag_attrs + "/>"; - } - else { - return "<"+ tag + tag_attrs + ">" + content.join( "" ) + ""; - } -} - -function convert_tree_to_html( tree, references, options ) { - var i; - options = options || {}; - - // shallow clone - var jsonml = tree.slice( 0 ); - - if ( typeof options.preprocessTreeNode === "function" ) { - jsonml = options.preprocessTreeNode(jsonml, references); - } - - // Clone attributes if they exist - var attrs = extract_attr( jsonml ); - if ( attrs ) { - jsonml[ 1 ] = {}; - for ( i in attrs ) { - jsonml[ 1 ][ i ] = attrs[ i ]; - } - attrs = jsonml[ 1 ]; - } - - // basic case - if ( typeof jsonml === "string" ) { - return jsonml; - } - - // convert this node - switch ( jsonml[ 0 ] ) { - case "header": - jsonml[ 0 ] = "h" + jsonml[ 1 ].level; - delete jsonml[ 1 ].level; - break; - case "bulletlist": - jsonml[ 0 ] = "ul"; - break; - case "numberlist": - jsonml[ 0 ] = "ol"; - break; - case "listitem": - jsonml[ 0 ] = "li"; - break; - case "para": - jsonml[ 0 ] = "p"; - break; - case "markdown": - jsonml[ 0 ] = "html"; - if ( attrs ) delete attrs.references; - break; - case "code_block": - jsonml[ 0 ] = "pre"; - i = attrs ? 2 : 1; - var code = [ "code" ]; - code.push.apply( code, jsonml.splice( i, jsonml.length - i ) ); - jsonml[ i ] = code; - break; - case "inlinecode": - jsonml[ 0 ] = "code"; - break; - case "img": - jsonml[ 1 ].src = jsonml[ 1 ].href; - delete jsonml[ 1 ].href; - break; - case "linebreak": - jsonml[ 0 ] = "br"; - break; - case "link": - jsonml[ 0 ] = "a"; - break; - case "link_ref": - jsonml[ 0 ] = "a"; - - // grab this ref and clean up the attribute node - var ref = references[ attrs.ref ]; - - // if the reference exists, make the link - if ( ref ) { - delete attrs.ref; - - // add in the href and title, if present - attrs.href = ref.href; - if ( ref.title ) { - attrs.title = ref.title; - } - - // get rid of the unneeded original text - delete attrs.original; - } - // the reference doesn't exist, so revert to plain text - else { - return attrs.original; - } - break; - case "img_ref": - jsonml[ 0 ] = "img"; - - // grab this ref and clean up the attribute node - var ref = references[ attrs.ref ]; - - // if the reference exists, make the link - if ( ref ) { - delete attrs.ref; - - // add in the href and title, if present - attrs.src = ref.href; - if ( ref.title ) { - attrs.title = ref.title; - } - - // get rid of the unneeded original text - delete attrs.original; - } - // the reference doesn't exist, so revert to plain text - else { - return attrs.original; - } - break; - } - - // convert all the children - i = 1; - - // deal with the attribute node, if it exists - if ( attrs ) { - // if there are keys, skip over it - for ( var key in jsonml[ 1 ] ) { - i = 2; - } - // if there aren't, remove it - if ( i === 1 ) { - jsonml.splice( i, 1 ); - } - } - - for ( ; i < jsonml.length; ++i ) { - jsonml[ i ] = convert_tree_to_html( jsonml[ i ], references, options ); - } - - return jsonml; -} - - -// merges adjacent text nodes into a single node -function merge_text_nodes( jsonml ) { - // skip the tag name and attribute hash - var i = extract_attr( jsonml ) ? 2 : 1; - - while ( i < jsonml.length ) { - // if it's a string check the next item too - if ( typeof jsonml[ i ] === "string" ) { - if ( i + 1 < jsonml.length && typeof jsonml[ i + 1 ] === "string" ) { - // merge the second string into the first and remove it - jsonml[ i ] += jsonml.splice( i + 1, 1 )[ 0 ]; - } - else { - ++i; - } - } - // if it's not a string recurse - else { - merge_text_nodes( jsonml[ i ] ); - ++i; - } - } -} - -} )( (function() { - if ( typeof exports === "undefined" ) { - window.markdown = {}; - return window.markdown; - } - else { - return exports; - } -} )() ); -// Released under BSD license -// Copyright (c) 2013 Apollic Software, LLC -(function (expose) { - var Preprocesser, forEach; - - (function (Markdown) { - - // Tent markdown flavor (https://github.com/tent/tent.io/issues/180) - Markdown.dialects.Tent = { - block: { - // member name: fn(block, remaining_blocks) -> json markdown tree or undefined - - // Match inline urls - autolink: function autolink( block, next ) { - var urls = expose.extractUrlsWithIndices(block); - - if (!urls.length) { - // no urls matched - return; - } - - var autolink_items = []; - - var item; - for (var i = 0; i < urls.length; i++) { - item = urls[i]; - - if ( block.slice(0, item.indices[1] + 1).match(/\[[^\]]+\]\([^\)]+\)$/) ) { - // markdown link syntax, don't autolink - continue; - } - - if ( block.slice(item.indices[0] - 1, block.length).match(/^\[[^\]]+\]\([^\)]+\)/) ) { - // url inside markdown link display text, don't autolink - continue; - } - - if ( block.match('`') ) { - // check if the url is inside code backticks - - var _indices = [], - _regex = /`/g, - m = null; - while ( m = _regex.exec(block) ) { - _indices.push(m.index); - } - - var skip = false, - _last_index = null; - if ( _indices.length && (_indices.length % 2 === 0) ) { - for (var j = 0; j < _indices.length; j += 2) { - if ( (_indices[j] < item.indices[0]) && (_indices[j+1] > item.indices[1]) ) { - // matched url is inside code backticks, ignore - _last_index = _indices[j+1]; - skip = true; - } - } - } - - if (skip === true) { - // don't autolink - continue; - } - } - - // we're good to process this link - autolink_items.push(item) - } - - if (!autolink_items.length) { - // there's nothing to autolink - return; - } - - // wrap matched urls in links - - var jsonml = ["para"], - _block = block, - item = null, - index_offset = 0, - before = null; - - for (var i = 0; i < autolink_items.length; i++) { - item = autolink_items[i]; - - // process text before url - before = _block.slice(0, item.indices[0] + index_offset); - if (before.length) { - jsonml = jsonml.concat( this.processInline(before) ); - } - - // linkify url - jsonml.push(["link", { href: item.url }, item.url]); - - // discard processed text - // and update index offset - _block = _block.slice(item.indices[1] + index_offset, _block.length) - index_offset -= before.length + (item.indices[1] - item.indices[0]) - } - - // process remaining text - jsonml = jsonml.concat( this.processInline(_block) ); - - return [jsonml]; - }, - - // Taken from Markdown.dialects.Gruber.block.para - para: function para( block, next ) { - // everything's a para! - return [ ["para"].concat( this.processInline( block ) ) ]; - } - }, - - inline: { - // member pattern_or_regex: (text, match, tree) -> [ length, string_or_tree ] - // __x__ members are not patterns - // __call__ is called by Markdown.prototype.processInline() - - /* - * Reserved member functions: - */ - - // Taken from Markdown.dialect.Gruber.inline.__oneElement__ - __oneElement__: function oneElement( text, patterns_or_re, previous_nodes ) { - var m, - res, - lastIndex = 0; - - patterns_or_re = patterns_or_re || this.dialect.inline.__patterns__; - var re = new RegExp( "([\\s\\S]*?)(" + (patterns_or_re.source || patterns_or_re) + ")" ); - - m = re.exec( text ); - if (!m) { - // Just boring text - return [ text.length, text ]; - } - else if ( m[1] ) { - // Some un-interesting text matched. Return that first - return [ m[1].length, m[1] ]; - } - - var res; - if ( m[2] in this.dialect.inline ) { - res = this.dialect.inline[ m[2] ].call( - this, - text.substr( m.index ), m, previous_nodes || [] ); - } - // Default for now to make dev easier. just slurp special and output it. - res = res || [ m[2].length, m[2] ]; - return res; - }, - - // Taken from Markdown.dialect.Gruber.inline.__call__ - __call__: function inline( text, patterns ) { - - var out = [], - res; - - function add(x) { - //D:self.debug(" adding output", uneval(x)); - if ( typeof x == "string" && typeof out[out.length-1] == "string" ) - out[ out.length-1 ] += x; - else - out.push(x); - } - - while ( text.length > 0 ) { - res = this.dialect.inline.__oneElement__.call(this, text, patterns, out ); - text = text.substr( res.shift() ); - forEach(res, add ) - } - - return out; - }, - - /* - * Pattern member functions: - */ - - // Taken from Markdown.dialects.Gruber.inline - // These characters are intersting elsewhere, so have rules for them so that - // chunks of plain text blocks don't include them - "]": function () {}, - "}": function () {}, - - // Taken from Markdown.dialects.Gruber.inline["\\"] - // Modification: change escape chars (removed { } # + - . ! and added ~) - "\\": function escaped( text ) { - // [ length of input processed, node/children to add... ] - // Only esacape: \ ` * _ [ ] ( ) * ~ - if ( text.match( /^\\[\\`\*_\[\]()\~]/ ) ) - return [ 2, text.charAt( 1 ) ]; - else - // Not an esacpe - return [ 1, "\\" ]; - }, - - "*": function bold( text ) { - // Inline content is possible inside `bold text` - var res = Markdown.DialectHelpers.inline_until_char.call( this, text.substr(1), "*" ); - - // Not bold - if ( !res ) return [ 1, "*" ]; - - var consumed = 1 + res[ 0 ], - children = res[ 1 ]; - - - return [consumed, ["strong"].concat(children)] - }, - - "_": function italic( text ) { - // Inline content is possible inside `bold text` - var res = Markdown.DialectHelpers.inline_until_char.call( this, text.substr(1), "_" ); - - // Not bold - if ( !res ) return [ 1, "_" ]; - - var consumed = 1 + res[ 0 ], - children = res[ 1 ]; - - - return [consumed, ["em"].concat(children)] - }, - - "~": function italic( text ) { - // Inline content is possible inside `bold text` - var res = Markdown.DialectHelpers.inline_until_char.call( this, text.substr(1), "~" ); - - // Not bold - if ( !res ) return [ 1, "~" ]; - - var consumed = 1 + res[ 0 ], - children = res[ 1 ]; - - - return [consumed, ["del"].concat(children)] - }, - - // Taken from Markdown.dialects.Gruber.inline["["] - // Modification: Only allow the most basic link syntax. - "[": function link( text ) { - - var orig = String(text); - // Inline content is possible inside `link text` - var res = Markdown.DialectHelpers.inline_until_char.call( this, text.substr(1), "]" ); - - // No closing ']' found. Just consume the [ - if ( !res ) return [ 1, "[" ]; - - var consumed = 1 + res[ 0 ], - children = res[ 1 ], - link, - attrs; - - // At this point the first [...] has been parsed. See what follows to find - // out which kind of link we are (reference or direct url) - text = text.substr( consumed ); - - // [link text](/path/to/img.jpg) - // 1 <--- captures - // This will capture up to the last paren in the block. We then pull - // back based on if there a matching ones in the url - // ([here](/url/(test)) - // The parens have to be balanced - - var m = text.match( /^\(([^"']*)\)/ ); - if ( m ) { - var url = m[1]; - consumed += m[0].length; - - var open_parens = 1; // One open that isn't in the capture - for ( var len = 0; len < url.length; len++ ) { - switch ( url[len] ) { - case "(": - open_parens++; - break; - case ")": - if ( --open_parens == 0) { - consumed -= url.length - len; - url = url.substring(0, len); - } - break; - } - } - - // Process escapes only - url = this.dialect.inline.__call__.call( this, url, /\\/ )[0]; - - attrs = { href: url || "" }; - - link = [ "link", attrs ].concat( children ); - return [ consumed, link ]; - } - - // Just consume the "[" - return [ 1, "[" ]; - }, - - // Taken from Markdown.dialects.Gruber.inline["`"] - // Modification: Only allow a single opening backtick - "`": function inlineCode( text ) { - // Always skip over the opening tick. - var m = text.match( /(`)(([\s\S]*?)\1)/ ); - - if ( m && m[2] ) - return [ m[1].length + m[2].length, [ "inlinecode", m[3] ] ]; - else { - // No closing backtick, it's just text - return [ 1, "`" ]; - } - }, - - // Taken from Markdown.dialects.Gruber.inline[" \n"] - // Modification: Don't require spaces before \n - "\n": function lineBreak( text ) { - return [ 1, [ "linebreak" ] ]; - } - - } - } - - Markdown.buildBlockOrder ( Markdown.dialects.Tent.block ); - Markdown.buildInlinePatterns( Markdown.dialects.Tent.inline ); - - })( expose.Markdown ) - - // Don't mess with Array.prototype. Its not friendly - if ( Array.prototype.forEach ) { - forEach = function( arr, cb, thisp ) { - return arr.forEach( cb, thisp ); - }; - } - else { - forEach = function(arr, cb, thisp) { - for (var i = 0; i < arr.length; i++) { - cb.call(thisp || arr, arr[i], i, arr); - } - } - } - - Preprocesser = function ( options ) { - this.footnotes = options.footnotes || []; - this.preprocessors = [this.expandFootnoteLinkHrefs].concat(options.preprocessors || []); - } - - Preprocesser.prototype.expandFootnoteLinkHrefs = function ( jsonml ) { - // Skip over anything that isn't a link - if (jsonml[0] !== 'link') return jsonml; - - // Skip over links that arn't footnotes - if (!jsonml[1] || !jsonml[1].href || !/^\d+$/.test(jsonml[1].href)) return jsonml; - - // Get href from footnodes array - var index = parseInt(jsonml[1].href); - jsonml[1].href = this.footnotes[index]; - jsonml[1].onclick = "bungloo.entityProfile.showEntity(this, " + index + "); return false;" - jsonml[1].class = "name"; - - // Unlink node if footnote doesn't exist - if (!jsonml[1].href) { - return [null].concat(jsonml.slice(2)); - } - - return jsonml; - } - - Preprocesser.prototype.preprocessTreeNode = function ( jsonml, references ) { - for (var i=0, _len = this.preprocessors.length; i < _len; i++) { - var fn = this.preprocessors[i] - if (!(typeof fn === 'function')) continue; - jsonml = fn.call(this, jsonml, references); - } - return jsonml; - } - - // Pre-process all link nodes to expand the [text](index) footnote syntax to actual links - // and unlink non-existant footnote references. - // Pass options.footnotes = [ href, ... ] to expand footnote links - __toHTML__ = expose.toHTML; - expose.toHTML = function ( source, dialect, options ) { - options = options || {}; - if (dialect === 'Tent') { - if (!(typeof options.preprocessTreeNode === 'function')) { - preprocesser = new Preprocesser( options ); - options.preprocessTreeNode = function () { - return preprocesser.preprocessTreeNode.apply(preprocesser, arguments); - } - } - } - return __toHTML__.call(null, source, dialect, options); - } -})(function () { - if ( typeof exports === "undefined" ) { - window.markdown.extractUrlsWithIndices = window.twttr.extractUrlsWithIndices; - return window.markdown; - } - else { - exports.markdown = require('markdown').markdown; - exports.markdown.extractUrlsWithIndices = require('./link-matcher').extractUrlsWithIndices; - - return exports.markdown; - } -}()) diff --git a/WebKit/scripts/main.js b/WebKit/scripts/main.js index 64fcaca..8d783b9 100644 --- a/WebKit/scripts/main.js +++ b/WebKit/scripts/main.js @@ -7,15 +7,14 @@ var bungloo = { entityProfile: null, conversation: null, search: null, - cache: { profiles: {}}, - newpost: null + cache: {} }; requirejs.config({ baseUrl: 'scripts' }); -function start(view, callback) { +function start(view) { if (view == "oauth") { @@ -25,24 +24,6 @@ function start(view, callback) { }); - } else if (view == "conversation-standalone") { - - require(["controller/Conversation"], function(Conversation) { - - bungloo.conversation = new Conversation(true); - if(callback) callback(); - - }); - - } else if (view == "newpost") { - - require(["controller/NewPost"], function(NewPost) { - - bungloo.newpost = new NewPost(); - if(callback) callback(); - - }); - } else { @@ -63,13 +44,32 @@ function start(view, callback) { bungloo.conversation = new Conversation(); bungloo.search = new Search(); - bungloo.sidebar.showContentForTimeline(); }); } } +String.prototype.startsWith = function(prefix) { + return this.indexOf(prefix) === 0; +} + +String.prototype.endsWith = function(suffix) { + return this.match(suffix+"$") == suffix; +}; + +var __entityMap = { + "&": "&", + "<": "<", + ">": ">" +}; + +String.prototype.escapeHTML = function() { + return String(this).replace(/[&<>]/g, function (s) { + return __entityMap[s]; + }); +} + var console = { log: function(s) { if (OS_TYPE == "mac") { @@ -110,14 +110,6 @@ var console = { function loadJsPlugin(js_url) { if (js_url) { - - requirejs.config({ - baseUrl: 'scripts', - paths: { - plugins: js_url.replace("Plugin.js", '') - } - }); - var js_plugin = document.createElement("script"); js_plugin.type = "text/javascript"; js_plugin.src = js_url; @@ -139,7 +131,7 @@ function loadCssPlugin(css_url) { function debug(string) { if (typeof string != "string") { - string = JSON.stringify(string, null, ' '); + string = JSON.stringify(string); } console.debug(string); @@ -161,46 +153,4 @@ function go() { // wait untill everything is loaded }, 500); } -go(); - - -// String stuff -String.prototype.startsWith = function(prefix) { - return this.indexOf(prefix) === 0; -} - -String.prototype.endsWith = function(suffix) { - return this.match(suffix+"$") == suffix; -}; - -var __entityMap = { - "&": "&", - "<": "<", - ">": ">" -}; - -String.prototype.escapeHTML = function() { - return String(this).replace(/[&<>]/g, function (s) { - return __entityMap[s]; - }); -} - -String.prototype.hasArabicCharacter = function() { - var arregex = /[\u0600-\u06FF]/; - return arregex.test(this); -} - -String.prototype.escapeSpecialChars = function() { - return this.replace(/[\\]/g, '\\\\') - .replace(/[\"]/g, '\\\"') - .replace(/[\/]/g, '\\/') - .replace(/[\b]/g, '\\b') - .replace(/[\f]/g, '\\f') - .replace(/[\n]/g, '\\n') - .replace(/[\r]/g, '\\r') - .replace(/[\t]/g, '\\t'); -} - -String.prototype.escapeRegExp = function() { - return this.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); -} \ No newline at end of file +go(); \ No newline at end of file diff --git a/Windows/deploy.ps1 b/Windows/deploy.ps1 deleted file mode 100644 index f4ec800..0000000 --- a/Windows/deploy.ps1 +++ /dev/null @@ -1,13 +0,0 @@ - -mkdir bungloo -Copy-Item ../Qt/* bungloo -Recurse -Copy-Item ../WebKit bungloo -Recurse -Copy-Item ../images bungloo -Recurse -Copy-Item setup.py bungloo -touch bungloo/__init__.py -Copy-Item msvcp90.dll bungloo -cd bungloo -python setup.py py2exe -cd .. -iscc.exe "installer.iss" -rm bungloo \ No newline at end of file diff --git a/Windows/installer.iss b/Windows/installer.iss deleted file mode 100644 index f01a595..0000000 --- a/Windows/installer.iss +++ /dev/null @@ -1,57 +0,0 @@ -; Script generated by the Inno Setup Script Wizard. -; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! - -#define MyAppName "Bungloo" -#define MyAppVersion "2.0.0" -#define MyAppPublisher "Jabs Nu" -#define MyAppURL "http://jabs.nu/bungloo" -#define MyAppExeName "Bungloo.exe" - -[Setup] -; NOTE: The value of AppId uniquely identifies this application. -; Do not use the same AppId value in installers for other applications. -; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) -AppId={{5E44EE00-8ECE-40C8-AF6F-70397DD1DBFE} -AppName={#MyAppName} -AppVersion={#MyAppVersion} -;AppVerName={#MyAppName} {#MyAppVersion} -AppPublisher={#MyAppPublisher} -AppPublisherURL={#MyAppURL} -AppSupportURL={#MyAppURL} -AppUpdatesURL={#MyAppURL} -DefaultDirName={pf}\{#MyAppName} -DefaultGroupName={#MyAppName} -AllowNoIcons=yes -LicenseFile=..\LICENSE.txt -OutputBaseFilename=setup -SetupIconFile=..\images\Icon.ico -Compression=lzma -SolidCompression=yes - -[Languages] -Name: "english"; MessagesFile: "compiler:Default.isl" - -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked -Name: "quicklaunchicon"; Description: "{cm:CreateQuickLaunchIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked; OnlyBelowVersion: 0,6.1 - -[Files] -Source: "bungloo\dist\Bungloo.exe"; DestDir: "{app}"; Flags: ignoreversion -Source: "bungloo\dist\library.zip"; DestDir: "{app}"; Flags: ignoreversion -Source: "bungloo\dist\*.pyd"; DestDir: "{app}"; Flags: ignoreversion -Source: "bungloo\dist\*.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "bungloo\dist\w9xpopen.exe"; DestDir: "{app}"; Flags: ignoreversion -Source: "bungloo\dist\images\*"; DestDir: "{app}\images"; Flags: ignoreversion recursesubdirs createallsubdirs -Source: "bungloo\dist\imageformats\*"; DestDir: "{app}\imageformats"; Flags: ignoreversion recursesubdirs createallsubdirs -Source: "bungloo\dist\WebKit\*"; DestDir: "{app}\WebKit"; Flags: ignoreversion recursesubdirs createallsubdirs -; NOTE: Don't use "Flags: ignoreversion" on any shared system files - -[Icons] -Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" -Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" -Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon -Name: "{userappdata}\Microsoft\Internet Explorer\Quick Launch\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: quicklaunchicon - -[Run] -Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent - diff --git a/Windows/msvcp90.dll b/Windows/msvcp90.dll deleted file mode 100644 index af6cc3d..0000000 Binary files a/Windows/msvcp90.dll and /dev/null differ diff --git a/Windows/setup.py b/Windows/setup.py deleted file mode 100644 index 1d9da92..0000000 --- a/Windows/setup.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python2 - -import os -from distutils.core import setup -import py2exe - -files = [] -for dirname, dirnames, filenames in os.walk('WebKit'): - for filename in filenames: - files += [(dirname, [os.path.join(dirname, filename)])] - -for dirname, dirnames, filenames in os.walk('images'): - for filename in filenames: - files += [(dirname, [os.path.join(dirname, filename)])] - -imageformats = [] -for dirname, dirnames, filenames in os.walk('C:\\Python27\\Lib\\site-packages\\PyQt4\\plugins\\imageformats'): - for filename in filenames: - imageformats += [os.path.join(dirname, filename)] - -files += [('imageformats', imageformats)] - -setup( - name = "Bungloo", - version = "2.0.0", - author = "Jeena Paradies", - author_email = "spam@jeenaparadies.net", - url = "http://jabs.nu/bungloo", - license = "BSD license", - data_files = files, - windows = [{ - 'script': "Bungloo.py", - 'icon_resources': [(1, 'images/Icon.ico')], - }], - options = { - "py2exe": { - "includes": ["sip", "ssl", "PyQt4.QtCore", "PyQt4.QtGui", "PyQt4.QtNetwork"], - } - } -) diff --git a/images/Actions-insert-image-icon.png b/images/Actions-insert-image-icon.png new file mode 100644 index 0000000..05adf9a Binary files /dev/null and b/images/Actions-insert-image-icon.png differ diff --git a/images/Icon.ico b/images/Icon.ico deleted file mode 100644 index 877fbfa..0000000 Binary files a/images/Icon.ico and /dev/null differ diff --git a/images/Icon16.png b/images/Icon16.png deleted file mode 100644 index 765b5c8..0000000 Binary files a/images/Icon16.png and /dev/null differ diff --git a/images/Icon248.png b/images/Icon248.png deleted file mode 100644 index 83d5450..0000000 Binary files a/images/Icon248.png and /dev/null differ diff --git a/images/Icon32.png b/images/Icon32.png deleted file mode 100644 index fed9bfc..0000000 Binary files a/images/Icon32.png and /dev/null differ diff --git a/images/Icon48.png b/images/Icon48.png deleted file mode 100644 index 71dbc57..0000000 Binary files a/images/Icon48.png and /dev/null differ diff --git a/images/Lock-Lock-icon.png b/images/Lock-Lock-icon.png new file mode 100644 index 0000000..45079c9 Binary files /dev/null and b/images/Lock-Lock-icon.png differ diff --git a/images/Lock-Unlock-icon.png b/images/Lock-Unlock-icon.png new file mode 100644 index 0000000..627d59f Binary files /dev/null and b/images/Lock-Unlock-icon.png differ diff --git a/WebKit/img/send.png b/images/glyphicons_123_message_out.png similarity index 100% rename from WebKit/img/send.png rename to images/glyphicons_123_message_out.png diff --git a/WebKit/img/images.png b/images/glyphicons_138_picture.png similarity index 100% rename from WebKit/img/images.png rename to images/glyphicons_138_picture.png diff --git a/WebKit/img/private.png b/images/glyphicons_203_lock.png similarity index 100% rename from WebKit/img/private.png rename to images/glyphicons_203_lock.png diff --git a/WebKit/img/public.png b/images/glyphicons_204_unlock.png similarity index 100% rename from WebKit/img/public.png rename to images/glyphicons_204_unlock.png diff --git a/readme.md b/readme.md index 6173013..72227e2 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@ Bungloo ======= -Bungloo is a slim Tent client for OS X, Linux and Windows written in mostly JavaScript. +Bungloo is a slim Tent client for OS X and Linux written in mostly JavaScript. For more info check out the Wiki page: https://github.com/jeena/Bungloo/wiki @@ -21,4 +21,3 @@ Thanks everyone in the Open Source community! Bungloo is using: - PyQt - http://wiki.python.org/moin/PyQt - Icon - http://www.fasticon.com - Linux monochrome icons - http://glyphicons.com -- py2exe - http://www.py2exe.org