3 commits - moksha/api moksha/lib moksha/public
by John (J5) Palmieri
moksha/api/widgets/containers/tabbedcontainer.py | 27
moksha/lib/helpers.py | 12
moksha/public/javascript/jquery.history.js | 150 +++++
moksha/public/javascript/ui/moksha.ui.tabs.js | 625 +++++++++++++++++++++++
4 files changed, 803 insertions(+), 11 deletions(-)
New commits:
commit 6f57f83564e8e3cfe78b4f11d3d2410b8d424f76
Merge: 9ea39da... ccc54d9...
Author: John (J5) Palmieri <johnp(a)redhat.com>
Date: Wed Feb 11 15:41:29 2009 -0500
Merge branch 'master' of git+ssh://johnp@git.fedorahosted.org/git/moksha
commit 9ea39dac9cd1375fff33a787b410e82f5d83ad17
Author: John (J5) Palmieri <johnp(a)redhat.com>
Date: Wed Feb 11 15:39:58 2009 -0500
implement some hash rewriting
* we had to copy and paste jquery.ui.tabs because subclassing isn't working
diff --git a/moksha/api/widgets/containers/tabbedcontainer.py b/moksha/api/widgets/containers/tabbedcontainer.py
index 00e5898..fc5577b 100644
--- a/moksha/api/widgets/containers/tabbedcontainer.py
+++ b/moksha/api/widgets/containers/tabbedcontainer.py
@@ -1,9 +1,12 @@
-from tw.jquery.ui_tabs import JQueryUITabs
-from tw.api import Widget
+from tw.jquery.ui_tabs import JQueryUITabs, jquery_ui_tabs_js
+from tw.api import Widget, JSLink, js_function
+from tw.forms import FormField
from pylons import config, request
from repoze.what import predicates
from moksha.lib.helpers import eval_app_config, ConfigWrapper
+moksha_ui_tabs_js = JSLink(modname='moksha', filename='public/javascript/ui/moksha.ui.tabs.js', javascript=[jquery_ui_tabs_js])
+
import urllib
class TabbedContainerTabs(Widget):
@@ -15,11 +18,13 @@ class TabbedContainerPanes(Widget):
tabwidget = TabbedContainerTabs('tabs')
panewidget = TabbedContainerPanes('panes')
+jQuery = js_function('jQuery')
+
"""
:Name: TabbedContainer
:Type: Container
"""
-class TabbedContainer(JQueryUITabs):
+class TabbedContainer(FormField):
"""
:tabs: An ordered list of application tabs to display
Application descriptors come from the config wrappers in
@@ -43,10 +48,21 @@ class TabbedContainer(JQueryUITabs):
template = 'mako:moksha.api.widgets.containers.templates.tabbedcontainer'
config_key = None # if set load config
tabs = ()
-
+ javascript = [moksha_ui_tabs_js
+ ]
+ params = ["tabdefault"]
+ tabdefault__doc="0-based index of the tab to be selected on page load"
+ tabdefault='#my_profile'
+# include_dynamic_js_calls = True #????
def update_params(self, d):
-
super(TabbedContainer, self).update_params(d)
+ if not getattr(d,"id",None):
+ raise ValueError, "JQueryUITabs is supposed to have id"
+
+ o = {
+ 'tabdefault': d.get('tabdefault', 0)
+ }
+ self.add_call(jQuery("#%s" % d.id).mokshatabs(o))
tabs = eval_app_config(config.get(self.config_key, "None"))
if not tabs:
@@ -62,4 +78,3 @@ class TabbedContainer(JQueryUITabs):
d['tabwidget'] = tabwidget
d['panewidget'] = panewidget
d['root_id'] = d['id']
-
diff --git a/moksha/lib/helpers.py b/moksha/lib/helpers.py
index 43bcc15..fa891e2 100644
--- a/moksha/lib/helpers.py
+++ b/moksha/lib/helpers.py
@@ -158,7 +158,7 @@ class App(ConfigWrapper):
if self.params:
query_str = "?" + urllib.urlencode(self.params)
- id = str(uuid.uuid4())
+ id = 'uuid' + str(uuid.uuid4())
return {'label': self.label, 'url': self.url + query_str, 'id': id,
'content_id': self.content_id + '-' + id}
@@ -251,7 +251,7 @@ class Widget(ConfigWrapper):
self.widget = widget
self.params = params or {}
self.auth = auth or []
- self.id = str(uuid.uuid4())
+ self.id = 'uuid' + str(uuid.uuid4())
self.content_id = content_id
if self.label and not content_id:
self.content_id = scrub_filter.sub('_', self.label.lower())
diff --git a/moksha/public/javascript/jquery.history.js b/moksha/public/javascript/jquery.history.js
new file mode 100644
index 0000000..14e4082
--- /dev/null
+++ b/moksha/public/javascript/jquery.history.js
@@ -0,0 +1,150 @@
+/*
+ * jQuery history plugin
+ *
+ * Copyright (c) 2006 Taku Sano (Mikage Sawatari)
+ * Licensed under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * Modified by Lincoln Cooper to add Safari support and only call the callback once during initialization
+ * for msie when no initial hash supplied.
+ */
+
+
+jQuery.extend({
+ historyCurrentHash: undefined,
+
+ historyCallback: undefined,
+
+ historyInit: function(callback){
+ jQuery.historyCallback = callback;
+ var current_hash = location.hash;
+
+ jQuery.historyCurrentHash = current_hash;
+ if(jQuery.browser.msie) {
+ // To stop the callback firing twice during initilization if no hash present
+ if (jQuery.historyCurrentHash == '') {
+ jQuery.historyCurrentHash = '#';
+ }
+
+ // add hidden iframe for IE
+ $("body").prepend('<iframe id="jQuery_history" style="display: none;"></iframe>');
+ var ihistory = $("#jQuery_history")[0];
+ var iframe = ihistory.contentWindow.document;
+ iframe.open();
+ iframe.close();
+ iframe.location.hash = current_hash;
+ }
+ else if ($.browser.safari) {
+ // etablish back/forward stacks
+ jQuery.historyBackStack = [];
+ jQuery.historyBackStack.length = history.length;
+ jQuery.historyForwardStack = [];
+
+ jQuery.isFirst = true;
+ }
+ jQuery.historyCallback(current_hash.replace(/^#/, ''));
+ setInterval(jQuery.historyCheck, 100);
+ },
+
+ historyAddHistory: function(hash) {
+ // This makes the looping function do something
+ jQuery.historyBackStack.push(hash);
+
+ jQuery.historyForwardStack.length = 0; // clear forwardStack (true click occured)
+ this.isFirst = true;
+ },
+
+ historyCheck: function(){
+ if(jQuery.browser.msie) {
+ // On IE, check for location.hash of iframe
+ var ihistory = $("#jQuery_history")[0];
+ var iframe = ihistory.contentDocument || ihistory.contentWindow.document;
+ var current_hash = iframe.location.hash;
+ if(current_hash != jQuery.historyCurrentHash) {
+
+ location.hash = current_hash;
+ jQuery.historyCurrentHash = current_hash;
+ jQuery.historyCallback(current_hash.replace(/^#/, ''));
+
+ }
+ } else if ($.browser.safari) {
+ if (!jQuery.dontCheck) {
+ var historyDelta = history.length - jQuery.historyBackStack.length;
+
+ if (historyDelta) { // back or forward button has been pushed
+ jQuery.isFirst = false;
+ if (historyDelta < 0) { // back button has been pushed
+ // move items to forward stack
+ for (var i = 0; i < Math.abs(historyDelta); i++) jQuery.historyForwardStack.unshift(jQuery.historyBackStack.pop());
+ } else { // forward button has been pushed
+ // move items to back stack
+ for (var i = 0; i < historyDelta; i++) jQuery.historyBackStack.push(jQuery.historyForwardStack.shift());
+ }
+ var cachedHash = jQuery.historyBackStack[jQuery.historyBackStack.length - 1];
+ if (cachedHash != undefined) {
+ jQuery.historyCurrentHash = location.hash;
+ jQuery.historyCallback(cachedHash);
+ }
+ } else if (jQuery.historyBackStack[jQuery.historyBackStack.length - 1] == undefined && !jQuery.isFirst) {
+ // back button has been pushed to beginning and URL already pointed to hash (e.g. a bookmark)
+ // document.URL doesn't change in Safari
+ if (document.URL.indexOf('#') >= 0) {
+ jQuery.historyCallback(document.URL.split('#')[1]);
+ } else {
+ var current_hash = location.hash;
+ jQuery.historyCallback('');
+ }
+ jQuery.isFirst = true;
+ }
+ }
+ } else {
+ // otherwise, check for location.hash
+ var current_hash = location.hash;
+ if(current_hash != jQuery.historyCurrentHash) {
+ jQuery.historyCurrentHash = current_hash;
+ jQuery.historyCallback(current_hash.replace(/^#/, ''));
+ }
+ }
+ },
+ historyLoad: function(hash){
+ var newhash;
+
+ if (jQuery.browser.safari) {
+ newhash = hash;
+ }
+ else {
+ newhash = '#' + hash;
+ location.hash = newhash;
+ }
+ jQuery.historyCurrentHash = newhash;
+
+ if(jQuery.browser.msie) {
+ var ihistory = $("#jQuery_history")[0];
+ var iframe = ihistory.contentWindow.document;
+ iframe.open();
+ iframe.close();
+ iframe.location.hash = newhash;
+ jQuery.historyCallback(hash);
+ }
+ else if (jQuery.browser.safari) {
+ jQuery.dontCheck = true;
+ // Manually keep track of the history values for Safari
+ this.historyAddHistory(hash);
+
+ // Wait a while before allowing checking so that Safari has time to update the "history" object
+ // correctly (otherwise the check loop would detect a false change in hash).
+ var fn = function() {jQuery.dontCheck = false;};
+ window.setTimeout(fn, 200);
+ jQuery.historyCallback(hash);
+ // N.B. "location.hash=" must be the last line of code for Safari as execution stops afterwards.
+ // By explicitly using the "location.hash" command (instead of using a variable set to "location.hash") the
+ // URL in the browser and the "history" object are both updated correctly.
+ location.hash = newhash;
+ }
+ else {
+ jQuery.historyCallback(hash);
+ }
+ }
+});
+
+
diff --git a/moksha/public/javascript/ui/moksha.ui.tabs.js b/moksha/public/javascript/ui/moksha.ui.tabs.js
new file mode 100644
index 0000000..d09c6f7
--- /dev/null
+++ b/moksha/public/javascript/ui/moksha.ui.tabs.js
@@ -0,0 +1,625 @@
+/*
+ * Moksha UI Tabs
+ *
+ * Taken from JQuery.UI.Tabs - use this for now until we can subclass
+ * Dual licensed under the MIT (MIT-LICENSE.txt)
+ * and GPL (GPL-LICENSE.txt) licenses.
+ *
+ * http://docs.jquery.com/UI/Tabs
+ *
+ * Depends:
+ * ui.core.js
+ */
+
+ // This is a hack for now since each
+ // level may consume more than just one element
+ if (typeof(_moksha_hash_consumer_level) == "undefined")
+ _moksha_hash_consumer_level = 0;
+ else
+ _moksha_hash_consumer_level++;
+
+(function($) {
+
+$.widget("ui.mokshatabs", {
+
+ init: function() {
+ this.options.event += '.tabs'; // namespace event
+
+ // create tabs
+ this.tabify(true);
+ },
+ setData: function(key, value) {
+ if ((/^selected/).test(key))
+ this.select(value);
+ else {
+ this.options[key] = value;
+ this.tabify();
+ }
+ },
+ length: function() {
+ return this.$tabs.length;
+ },
+ tabId: function(a) {
+ return a.title && a.title.replace(/\s/g, '_').replace(/[^A-Za-z0-9\-_:\.]/g, '')
+ || this.options.idPrefix + $.data(a);
+ },
+ ui: function(tab, panel) {
+ return {
+ options: this.options,
+ tab: tab,
+ panel: panel,
+ index: this.$tabs.index(tab)
+ };
+ },
+ tabify: function(init) {
+
+ this.$lis = $('ul:first>li:has(a[href])', this.element);
+ this.$tabs = this.$lis.map(function() { return $('a', this)[0]; });
+ this.$panels = $([]);
+
+ var self = this, o = this.options;
+
+ self.options.hash_level = _moksha_hash_consumer_level;
+ this.$tabs.each(function(i, a) {
+ // inline tab
+ if (a.hash && a.hash.replace('#', '')) // Safari 2 reports '#' for an empty hash
+ self.$panels = self.$panels.add(a.hash);
+ // remote tab
+ else if ($(a).attr('href') != '#') { // prevent loading the page itself if href is just "#"
+ $.data(a, 'href.tabs', a.href); // required for restore on destroy
+ $.data(a, 'load.tabs', a.href); // mutable
+ var id = self.tabId(a);
+ a.href = '#' + id;
+ var $panel = $('#' + id + ':first', self.element);
+ if (!$panel.length) {
+ $panel = $(o.panelTemplate).attr('id', id).addClass(o.panelClass)
+ .insertAfter( self.$panels[i - 1] || self.element );
+ $panel.data('destroy.tabs', true);
+ }
+ self.$panels = self.$panels.add( $panel );
+ }
+ // invalid tab href
+ else
+ o.disabled.push(i + 1);
+ });
+
+ if (init) {
+
+ // attach necessary classes for styling if not present
+ this.element.addClass(o.navClass);
+ if (jQuery(this.element).effectivedirection() == 'rtl') {
+ this.element.addClass(o.navClass_rtl);
+ }
+ this.$panels.each(function() {
+ var $this = $(this);
+ $this.addClass(o.panelClass);
+ });
+
+ // Selected tab
+ // use "selected" option or try to retrieve:
+ // 1. from fragment identifier in url
+ // 2. from cookie
+ // 3. from selected class attribute on <li>
+ if (o.selected === undefined) {
+ if (location.hash) {
+ var index = this.hashToIndex(location.hash, o.hash_level);
+
+ if (index >= 0) {
+ o.selected = index;
+ // prevent page scroll to fragment
+ if ($.browser.msie || $.browser.opera) { // && !o.remote
+ var $toShow = $(this.$tabs[index]);
+ var toShowId = $toShow.attr('id');
+ $toShow.attr('id', '');
+ setTimeout(function() {
+ $toShow.attr('id', toShowId); // restore id
+ }, 500);
+ }
+ scrollTo(0, 0);
+ }
+
+ }
+ else if (o.cookie) {
+ var index = parseInt($.cookie('ui-tabs' + $.data(self.element)),10);
+ if (index && self.$tabs[index])
+ o.selected = index;
+ }
+ else if (self.$lis.filter('.' + o.selectedClass).length)
+ o.selected = self.$lis.index( self.$lis.filter('.' + o.selectedClass)[0] );
+ }
+ o.selected = o.selected === null || o.selected !== undefined ? o.selected : 0; // first tab selected by default
+
+ // Take disabling tabs via class attribute from HTML
+ // into account and update option properly.
+ // A selected tab cannot become disabled.
+ o.disabled = $.unique(o.disabled.concat(
+ $.map(this.$lis.filter('.' + o.disabledClass),
+ function(n, i) { return self.$lis.index(n); } )
+ )).sort();
+ if ($.inArray(o.selected, o.disabled) != -1)
+ o.disabled.splice($.inArray(o.selected, o.disabled), 1);
+
+ // highlight selected tab
+ this.$panels.addClass(o.hideClass);
+ this.$lis.removeClass(o.selectedClass);
+ if (o.selected !== null) {
+
+ this.$panels.eq(o.selected).show().removeClass(o.hideClass); // use show and remove class to show in any case no matter how it has been hidden before
+ this.$lis.eq(o.selected).addClass(o.selectedClass);
+
+ // seems to be expected behavior that the show callback is fired
+ var onShow = function() {
+ $(self.element).triggerHandler('tabsshow',
+ [self.fakeEvent('tabsshow'), self.ui(self.$tabs[o.selected], self.$panels[o.selected])], o.show);
+ };
+
+ // load if remote tab
+ if ($.data(this.$tabs[o.selected], 'load.tabs')) {
+ this.load(o.selected, onShow);
+ // just trigger show event
+ } else
+ onShow();
+
+ }
+
+ // clean up to avoid memory leaks in certain versions of IE 6
+ $(window).bind('unload', function() {
+ self.$tabs.unbind('.tabs');
+ self.$lis = self.$tabs = self.$panels = null;
+ });
+
+ }
+
+ // disable tabs
+ for (var i = 0, li; li = this.$lis[i]; i++)
+ $(li)[$.inArray(i, o.disabled) != -1 && !$(li).hasClass(o.selectedClass) ? 'addClass' : 'removeClass'](o.disabledClass);
+
+ // reset cache if switching from cached to not cached
+ if (o.cache === false)
+ this.$tabs.removeData('cache.tabs');
+
+ // set up animations
+ var hideFx, showFx, baseFx = { 'min-width': 0, duration: 1 }, baseDuration = 'normal';
+ if (o.fx && o.fx.constructor == Array)
+ hideFx = o.fx[0] || baseFx, showFx = o.fx[1] || baseFx;
+ else
+ hideFx = showFx = o.fx || baseFx;
+
+ // reset some styles to maintain print style sheets etc.
+ var resetCSS = { display: '', overflow: '', height: '' };
+ if (!$.browser.msie) // not in IE to prevent ClearType font issue
+ resetCSS.opacity = '';
+
+ // Hide a tab, animation prevents browser scrolling to fragment,
+ // $show is optional.
+ function hideTab(clicked, $hide, $show) {
+ $hide.animate(hideFx, hideFx.duration || baseDuration, function() { //
+ $hide.addClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
+ if ($.browser.msie && hideFx.opacity)
+ $hide[0].style.filter = '';
+ if ($show)
+ showTab(clicked, $show, $hide);
+ });
+ }
+
+ // Show a tab, animation prevents browser scrolling to fragment,
+ // $hide is optional.
+ function showTab(clicked, $show, $hide) {
+ if (showFx === baseFx)
+ $show.css('display', 'block'); // prevent occasionally occuring flicker in Firefox cause by gap between showing and hiding the tab panels
+ $show.animate(showFx, showFx.duration || baseDuration, function() {
+ $show.removeClass(o.hideClass).css(resetCSS); // maintain flexible height and accessibility in print etc.
+ if ($.browser.msie && showFx.opacity)
+ $show[0].style.filter = '';
+
+ // callback
+ $(self.element).triggerHandler('tabsshow',
+ [self.fakeEvent('tabsshow'), self.ui(clicked, $show[0])], o.show);
+
+ });
+ }
+
+ // switch a tab
+ function switchTab(clicked, $li, $hide, $show) {
+ /*if (o.bookmarkable && trueClick) { // add to history only if true click occured, not a triggered click
+ $.ajaxHistory.update(clicked.hash);
+ }*/
+ $li.addClass(o.selectedClass)
+ .siblings().removeClass(o.selectedClass);
+ hideTab(clicked, $hide, $show);
+ }
+
+ // attach tab event handler, unbind to avoid duplicates from former tabifying...
+ this.$tabs.unbind('.tabs').bind(o.event, function() {
+
+ //var trueClick = e.clientX; // add to history only if true click occured, not a triggered click
+ var $li = $(this).parents('li:eq(0)'),
+ $hide = self.$panels.filter(':visible'),
+ $show = $(this.hash + ':first', self.element);
+
+ // If tab is already selected and not unselectable or tab disabled or
+ // or is already loading or click callback returns false stop here.
+ // Check if click handler returns false last so that it is not executed
+ // for a disabled or loading tab!
+ if (($li.hasClass(o.selectedClass) && !o.unselect)
+ || $li.hasClass(o.disabledClass)
+ || $(this).hasClass(o.loadingClass)
+ || $(self.element).triggerHandler('tabsselect', [self.fakeEvent('tabsselect'), self.ui(this, $show[0])], o.select) === false
+ ) {
+ this.blur();
+ return false;
+ }
+
+ self.options.selected = self.$tabs.index(this);
+
+ var $el = $(this)
+ var href = $el.attr('href');
+ href = href.split("-uuid")[0];
+
+ //only update the hash level we care about
+ if (o.hash_level != 0) {
+ var hash = location.hash.substr(1);
+ hash = hash.split('/');
+ hash[o.hash_level] = href.substr(1);
+
+ hash = '#' + hash.splice(0, o.hash_level + 1).join('/');
+ location.hash = hash;
+ } else {
+ location.hash = href;
+ }
+
+ // if tab may be closed
+ if (o.unselect) {
+ if ($li.hasClass(o.selectedClass)) {
+ self.options.selected = null;
+ $li.removeClass(o.selectedClass);
+ self.$panels.stop();
+ hideTab(this, $hide);
+ this.blur();
+ return false;
+ } else if (!$hide.length) {
+ self.$panels.stop();
+ var a = this;
+ self.load(self.$tabs.index(this), function() {
+ $li.addClass(o.selectedClass).addClass(o.unselectClass);
+ showTab(a, $show);
+ });
+ this.blur();
+ return false;
+ }
+ }
+
+ if (o.cookie)
+ $.cookie('ui-tabs' + $.data(self.element), self.options.selected, o.cookie);
+
+ // stop possibly running animations
+ self.$panels.stop();
+
+ // show new tab
+ if ($show.length) {
+
+ // prevent scrollbar scrolling to 0 and than back in IE7, happens only if bookmarking/history is enabled
+ /*if ($.browser.msie && o.bookmarkable) {
+ var showId = this.hash.replace('#', '');
+ $show.attr('id', '');
+ setTimeout(function() {
+ $show.attr('id', showId); // restore id
+ }, 0);
+ }*/
+
+ var a = this;
+ self.load(self.$tabs.index(this), $hide.length ?
+ function() {
+ switchTab(a, $li, $hide, $show);
+ } :
+ function() {
+ $li.addClass(o.selectedClass);
+ showTab(a, $show);
+ }
+ );
+
+ // Set scrollbar to saved position - need to use timeout with 0 to prevent browser scroll to target of hash
+ /*var scrollX = window.pageXOffset || document.documentElement && document.documentElement.scrollLeft || document.body.scrollLeft || 0;
+ var scrollY = window.pageYOffset || document.documentElement && document.documentElement.scrollTop || document.body.scrollTop || 0;
+ setTimeout(function() {
+ scrollTo(scrollX, scrollY);
+ }, 0);*/
+
+ } else
+ throw 'jQuery UI Tabs: Mismatching fragment identifier.';
+
+ // Prevent IE from keeping other link focussed when using the back button
+ // and remove dotted border from clicked link. This is controlled in modern
+ // browsers via CSS, also blur removes focus from address bar in Firefox
+ // which can become a usability and annoying problem with tabsRotate.
+ if ($.browser.msie)
+ this.blur();
+
+ //return o.bookmarkable && !!trueClick; // convert trueClick == undefined to Boolean required in IE
+ return false;
+
+ });
+
+ // disable click if event is configured to something else
+ if (!(/^click/).test(o.event))
+ this.$tabs.bind('click.tabs', function() { return false; });
+
+ },
+ add: function(url, label, index) {
+ if (index == undefined)
+ index = this.$tabs.length; // append by default
+
+ var o = this.options;
+ var $li = $(o.tabTemplate.replace(/#\{href\}/g, url).replace(/#\{label\}/g, label));
+ $li.data('destroy.tabs', true);
+
+ var id = url.indexOf('#') == 0 ? url.replace('#', '') : this.tabId( $('a:first-child', $li)[0] );
+
+ // try to find an existing element before creating a new one
+ var $panel = $('#' + id, this.element);
+ if (!$panel.length) {
+ $panel = $(o.panelTemplate).attr('id', id)
+ .addClass(o.hideClass)
+ .data('destroy.tabs', true);
+ }
+ $panel.addClass(o.panelClass);
+ if (index >= this.$lis.length) {
+ $li.appendTo(this.element);
+ $panel.appendTo(this.element[0].parentNode);
+ } else {
+ $li.insertBefore(this.$lis[index]);
+ $panel.insertBefore(this.$panels[index]);
+ }
+
+ o.disabled = $.map(o.disabled,
+ function(n, i) { return n >= index ? ++n : n });
+
+ this.tabify();
+
+ if (this.$tabs.length == 1) {
+ $li.addClass(o.selectedClass);
+ $panel.removeClass(o.hideClass);
+ var href = $.data(this.$tabs[0], 'load.tabs');
+ if (href)
+ this.load(index, href);
+ }
+
+ // callback
+ this.element.triggerHandler('tabsadd',
+ [this.fakeEvent('tabsadd'), this.ui(this.$tabs[index], this.$panels[index])], o.add
+ );
+ },
+ remove: function(index) {
+ var o = this.options, $li = this.$lis.eq(index).remove(),
+ $panel = this.$panels.eq(index).remove();
+
+ // If selected tab was removed focus tab to the right or
+ // in case the last tab was removed the tab to the left.
+ if ($li.hasClass(o.selectedClass) && this.$tabs.length > 1)
+ this.select(index + (index + 1 < this.$tabs.length ? 1 : -1));
+
+ o.disabled = $.map($.grep(o.disabled, function(n, i) { return n != index; }),
+ function(n, i) { return n >= index ? --n : n });
+
+ this.tabify();
+
+ // callback
+ this.element.triggerHandler('tabsremove',
+ [this.fakeEvent('tabsremove'), this.ui($li.find('a')[0], $panel[0])], o.remove
+ );
+ },
+ enable: function(index) {
+ var o = this.options;
+ if ($.inArray(index, o.disabled) == -1)
+ return;
+
+ var $li = this.$lis.eq(index).removeClass(o.disabledClass);
+ if ($.browser.safari) { // fix disappearing tab (that used opacity indicating disabling) after enabling in Safari 2...
+ $li.css('display', 'inline-block');
+ setTimeout(function() {
+ $li.css('display', 'block');
+ }, 0);
+ }
+
+ o.disabled = $.grep(o.disabled, function(n, i) { return n != index; });
+
+ // callback
+ this.element.triggerHandler('tabsenable',
+ [this.fakeEvent('tabsenable'), this.ui(this.$tabs[index], this.$panels[index])], o.enable
+ );
+
+ },
+ disable: function(index) {
+ var self = this, o = this.options;
+ if (index != o.selected) { // cannot disable already selected tab
+ this.$lis.eq(index).addClass(o.disabledClass);
+
+ o.disabled.push(index);
+ o.disabled.sort();
+
+ // callback
+ this.element.triggerHandler('tabsdisable',
+ [this.fakeEvent('tabsdisable'), this.ui(this.$tabs[index], this.$panels[index])], o.disable
+ );
+ }
+ },
+ // get the selected tab index give a location hash
+ hashToIndex: function(hash, level) {
+ var hash = location.hash;
+ var offset = 0;
+
+ //remove the has because we only care about the / delimiter
+ if (hash[0] == "#")
+ hash = hash.substr(1);
+
+ hash = hash.split("/");
+ // get the first id ignoring leading slashes
+ for (var i=0; i<hash.length, !hash[i]; i++) {
+ offset++;
+ }
+
+ var id_index = level + offset;
+ if (id_index >= hash.length)
+ return -1;
+
+ var id = "#" + hash[level + offset];
+
+ return this.idToIndex(id);
+ },
+ idToIndex: function(id) {
+ var index = -1;
+ var l = id.length;
+ for(var i=0; i < this.$tabs.length; i++) {
+ var h = $(this.$tabs[i]).attr('href');
+ // FIXME: you can't have two tabs where one is a substring of another
+ if (h.substr(0, l) == id) {
+ index = i;
+ break;
+ }
+ }
+
+ return (index);
+ },
+ select: function(index) {
+ if (typeof index == 'string')
+ index = this.idToIndex(index);
+
+ this.$tabs.eq(index).trigger(this.options.event);
+ },
+ load: function(index, callback) { // callback is for internal usage only
+
+ var self = this, o = this.options, $a = this.$tabs.eq(index), a = $a[0],
+ bypassCache = callback == undefined || callback === false, url = $a.data('load.tabs');
+
+ callback = callback || function() {};
+
+ // no remote or from cache - just finish with callback
+ if (!url || !bypassCache && $.data(a, 'cache.tabs')) {
+ callback();
+ return;
+ }
+
+ // load remote from here on
+
+ var inner = function(parent) {
+ var $parent = $(parent), $inner = $parent.find('*:last');
+ return $inner.length && $inner.is(':not(img)') && $inner || $parent;
+ };
+ var cleanup = function() {
+ self.$tabs.filter('.' + o.loadingClass).removeClass(o.loadingClass)
+ .each(function() {
+ if (o.spinner)
+ inner(this).parent().html(inner(this).data('label.tabs'));
+ });
+ self.xhr = null;
+ };
+
+ if (o.spinner) {
+ var label = inner(a).html();
+ inner(a).wrapInner('<em></em>')
+ .find('em').data('label.tabs', label).html(o.spinner);
+ }
+
+ var ajaxOptions = $.extend({}, o.ajaxOptions, {
+ url: url,
+ success: function(r, s) {
+ var $panel = $(a.hash + ':first', self.element);
+ $panel.html(r);
+ cleanup();
+
+ if (o.cache)
+ $.data(a, 'cache.tabs', true); // if loaded once do not load them again
+
+ // callbacks
+ $(self.element).triggerHandler('tabsload',
+ [self.fakeEvent('tabsload'), self.ui(self.$tabs[index], self.$panels[index])], o.load
+ );
+ o.ajaxOptions.success && o.ajaxOptions.success(r, s);
+
+ // This callback is required because the switch has to take
+ // place after loading has completed. Call last in order to
+ // fire load before show callback...
+ callback();
+ }
+ });
+ if (this.xhr) {
+ // terminate pending requests from other tabs and restore tab label
+ this.xhr.abort();
+ cleanup();
+ }
+ $a.addClass(o.loadingClass);
+ setTimeout(function() { // timeout is again required in IE, "wait" for id being restored
+ self.xhr = $.ajax(ajaxOptions);
+ }, 0);
+
+ },
+ url: function(index, url) {
+ this.$tabs.eq(index).removeData('cache.tabs').data('load.tabs', url);
+ },
+ destroy: function() {
+ var o = this.options;
+ this.element.unbind('.tabs')
+ .removeClass(o.navClass).removeData('tabs');
+ if (jQuery(this.element).effectivedirection() == 'rtl') {
+ jQuery(this.element).removeClass(o.navClass_rtl);
+ }
+ this.$tabs.each(function() {
+ var href = $.data(this, 'href.tabs');
+ if (href)
+ this.href = href;
+ var $this = $(this).unbind('.tabs');
+ $.each(['href', 'load', 'cache'], function(i, prefix) {
+ $this.removeData(prefix + '.tabs');
+ });
+ });
+ this.$lis.add(this.$panels).each(function() {
+ if ($.data(this, 'destroy.tabs'))
+ $(this).remove();
+ else
+ $(this).removeClass([o.selectedClass, o.unselectClass,
+ o.disabledClass, o.panelClass, o.hideClass].join(' '));
+ });
+ },
+ fakeEvent: function(type) {
+ return $.event.fix({
+ type: type,
+ target: this.element[0]
+ });
+ }
+});
+
+$.ui.mokshatabs.defaults = {
+ // basic setup
+ unselect: false,
+ event: 'click',
+ disabled: [],
+ cookie: null, // e.g. { expires: 7, path: '/', domain: 'jquery.com', secure: true }
+ // TODO history: false,
+
+ // Ajax
+ spinner: 'Loading…',
+ cache: false,
+ idPrefix: 'ui-tabs-',
+ ajaxOptions: {},
+
+ // animations
+ fx: null, // e.g. { height: 'toggle', opacity: 'toggle', duration: 200 }
+
+ // templates
+ tabTemplate: '<li><a href="#{href}"><span>#{label}</span></a></li>',
+ panelTemplate: '<div></div>',
+
+ // CSS classes
+ navClass: 'ui-tabs-nav',
+ navClass_rtl: 'ui-tabs-nav-rtl',
+ selectedClass: 'ui-tabs-selected',
+ unselectClass: 'ui-tabs-unselect',
+ disabledClass: 'ui-tabs-disabled',
+ panelClass: 'ui-tabs-panel',
+ hideClass: 'ui-tabs-hide',
+ loadingClass: 'ui-tabs-loading'
+};
+
+$.ui.mokshatabs.getter = "length";
+
+})(jQuery);
\ No newline at end of file
commit ea8e7372593b6f5407393a856761608b4c15b6aa
Author: John (J5) Palmieri <johnp(a)redhat.com>
Date: Tue Feb 10 15:58:53 2009 -0500
give all apps uuid's so there is no name conflicts
diff --git a/moksha/lib/helpers.py b/moksha/lib/helpers.py
index 01f88a7..43bcc15 100644
--- a/moksha/lib/helpers.py
+++ b/moksha/lib/helpers.py
@@ -158,10 +158,10 @@ class App(ConfigWrapper):
if self.params:
query_str = "?" + urllib.urlencode(self.params)
- id = uuid.uuid4()
+ id = str(uuid.uuid4())
return {'label': self.label, 'url': self.url + query_str, 'id': id,
- 'content_id': self.content_id}
+ 'content_id': self.content_id + '-' + id}
class MokshaApp(App):
"""A configuration wrapper class that displays a Moksa application
@@ -251,19 +251,21 @@ class Widget(ConfigWrapper):
self.widget = widget
self.params = params or {}
self.auth = auth or []
-
+ self.id = str(uuid.uuid4())
self.content_id = content_id
if self.label and not content_id:
self.content_id = scrub_filter.sub('_', self.label.lower())
+ self.content_id += '-' + self.id
+
def process(self):
if not check_predicates(self.auth):
return None
- id = uuid.uuid4()
+
url = '#' + self.content_id
return {'label': self.label, 'url': url,'widget': self.widget ,
- 'params':self.params, 'id': id, 'content_id': self.content_id}
+ 'params':self.params, 'id': self.id, 'content_id': self.content_id}
class MokshaWidget(Widget):
"""A configuration wrapper class that displays a ToscaWidget registered
15 years, 4 months
6 commits - apache/moksha.conf apache/moksha.wsgi moksha/api moksha/__init__.py start-moksha
by Luke Macken
apache/moksha.conf | 33 +++++++++++++++++++++++++++++++
apache/moksha.wsgi | 9 ++++++++
moksha/__init__.py | 3 +-
moksha/api/widgets/chat/static/style.css | 6 ++---
start-moksha | 6 +++--
5 files changed, 51 insertions(+), 6 deletions(-)
New commits:
commit ccc54d98fdac8e2efe9b4832ed0953637bff0fa1
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 11 12:46:08 2009 -0500
Add a moksha.wsgi application for mod_wsgi deployments
diff --git a/apache/moksha.wsgi b/apache/moksha.wsgi
new file mode 100644
index 0000000..3a426ff
--- /dev/null
+++ b/apache/moksha.wsgi
@@ -0,0 +1,9 @@
+import os, sys
+sys.path.append('/srv/moksha')
+os.environ['PYTHON_EGG_CACHE'] = '/srv/moksha/.python-eggs'
+
+#sys.stdout = sys.stderr
+
+from paste.deploy import loadapp
+
+application = loadapp('config:/srv/moksha/development.ini')
commit 0293853ce3de490f8cc1133f43762b9e209276a6
Author: Luke Macken <lmacken(a)redhat.com>
Date: Wed Feb 11 12:45:42 2009 -0500
Add a default apache configuration for moksha
diff --git a/apache/moksha.conf b/apache/moksha.conf
new file mode 100644
index 0000000..060d0b2
--- /dev/null
+++ b/apache/moksha.conf
@@ -0,0 +1,33 @@
+#MaxRequestsPerChild 100
+#HostnameLookups Off
+#Keepalive off
+
+# Default Python Home, with clean site-packages:
+WSGIPythonHome /srv/moksha/tg2env
+
+WSGIPythonEggs /srv/moksha/.python-eggs
+
+<VirtualHost 0.0.0.0:80>
+
+ SSLEngine off
+ DocumentRoot /srv/moksha
+ ServerName Moksha
+ ErrorLog logs/moksha_error_log
+ CustomLog logs/moksha_access_log combined
+
+ Alias /toscawidgets/ /srv/moksha/toscawidgets/
+ <Directory /srv/moksha/toscawidgets/>
+ Options -FollowSymLinks
+ AllowOverride None
+ Order allow,deny
+ Allow from all
+ </Directory>
+
+ WSGIScriptAlias / /srv/moksha/apache/moksha.wsgi
+
+ <Directory /srv/moksha/apache>
+ Order deny,allow
+ Allow from all
+ </Directory>
+
+</VirtualHost>
commit d5d67a823c011de1f00348f333be7f6a58cdff4a
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 10 17:07:57 2009 -0500
More start-moksha tweaking
diff --git a/start-moksha b/start-moksha
index 996ba8c..1c46b53 100755
--- a/start-moksha
+++ b/start-moksha
@@ -12,6 +12,7 @@ if [ ! $VIRTUAL_ENV ]; then
easy_install -U WebOb
easy_install -i http://www.turbogears.org/2.0/downloads/current/index tg.devtools
pushd moksha/widgetbrowser; python setup.py develop; popd
+ easy_install "tw.jquery==dev"
else
source tg2env/bin/activate
fi
commit a5d958265188c8fa1d126c146645bbb1040e7b23
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 10 16:59:59 2009 -0500
Include site-packages in our start-moksha, so we can pull in pysvn and mercurial
diff --git a/start-moksha b/start-moksha
index 79ece4c..996ba8c 100755
--- a/start-moksha
+++ b/start-moksha
@@ -4,13 +4,14 @@
if [ ! $VIRTUAL_ENV ]; then
if [ ! -d tg2env ]; then
echo "Initializing a TurboGears2 virtual environment"
- virtualenv --no-site-packages tg2env
- #virtualenv tg2env
+ # Enable site packages so we can yum install pysvn and mercurial
+ # in order to build Sphinx docs on the fly.
+ virtualenv tg2env
+ #virtualenv --no-site-packages tg2env
source tg2env/bin/activate
easy_install -U WebOb
easy_install -i http://www.turbogears.org/2.0/downloads/current/index tg.devtools
pushd moksha/widgetbrowser; python setup.py develop; popd
- easy_install "tw.jquery==dev"
else
source tg2env/bin/activate
fi
commit 07a7f55060fcb80a4e437b31fa1d6e5f04f1be99
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 10 16:59:31 2009 -0500
Make our chat widget colors a bit more moksha-themed
diff --git a/moksha/api/widgets/chat/static/style.css b/moksha/api/widgets/chat/static/style.css
index a19f9de..c92d64e 100644
--- a/moksha/api/widgets/chat/static/style.css
+++ b/moksha/api/widgets/chat/static/style.css
@@ -12,7 +12,7 @@ html, body {
right: 1px;
top: 1px;
padding: 2px;
- background: #005522;
+ background: #3f9824;
color: white;
font-weight: bold;
cursor: pointer;
@@ -81,9 +81,9 @@ html, body {
#popupContent {
font-size: 120%;
text-align:center;
- background: #005522;
+ background: #3f9824;
color: white;
- border: 5pt solid #50A572;
+ border: 5pt solid #83cb22;
padding: 8px;
padding-bottom: 20px;
width: 100%;
commit ba18a889f6c821a39e7d92d6c361737bac999415
Author: Luke Macken <lmacken(a)redhat.com>
Date: Tue Feb 10 14:12:29 2009 -0500
Be a little more careful when closing the feed storage on exit
diff --git a/moksha/__init__.py b/moksha/__init__.py
index c3b5e92..7ead770 100644
--- a/moksha/__init__.py
+++ b/moksha/__init__.py
@@ -28,4 +28,5 @@ def get_widget(name):
def shutdown():
""" Called when Moksha shuts down """
- feed_storage.close()
+ if feed_storage:
+ feed_storage.close()
15 years, 4 months
10 commits - development.ini docs/index.rst docs/main moksha/api moksha/config moksha/__init__.py moksha/middleware moksha/streams orbited.cfg
by Luke Macken
development.ini | 2 -
docs/index.rst | 4 +-
docs/main/Feeds.rst | 1
docs/main/MokshaApplications.rst | 58 +++++++++++++++++++-------------------
moksha/__init__.py | 16 +++++-----
moksha/api/menus/default.py | 2 -
moksha/api/menus/widgets.py | 2 -
moksha/api/streams/datastream.py | 2 -
moksha/api/widgets/feed/feed.py | 16 +++++++---
moksha/config/app_cfg.py | 3 +
moksha/middleware/middleware.py | 4 +-
moksha/streams/demo/demostream.py | 7 +++-
orbited.cfg | 4 +-
13 files changed, 68 insertions(+), 53 deletions(-)
New commits:
commit 1b82ac582b4cdc0be8918dcb662bf835141e9395
Author: Luke Macken <lmacken(a)redhat.com>
Date: Mon Feb 9 17:35:51 2009 -0500
Cleanly close our feed objects in our demo data stream
diff --git a/moksha/api/widgets/feed/feed.py b/moksha/api/widgets/feed/feed.py
index 9015575..b78337a 100644
--- a/moksha/api/widgets/feed/feed.py
+++ b/moksha/api/widgets/feed/feed.py
@@ -29,7 +29,8 @@ log = logging.getLogger(__name__)
# is unavailable. By default, it will try and use the centralized
# moksha.feed_cache, which is setup by the middleware, but will gracefully
# fallback to this cache.
-cache = None
+feed_storage = None
+feed_cache = None
class Feed(Widget):
""" A powerful Feed object.
@@ -95,10 +96,11 @@ class Feed(Widget):
else:
# MokshaMiddleware not running, so setup our own feed cache.
# This allows us to use this object outside of WSGI requests.
- global cache
- if not cache:
- cache = Cache(Shove('sqlite:///feeds.db', compress=True))
- feed = cache.fetch(url)
+ global feed_cache, feed_storage
+ if not feed_cache:
+ feed_storage = Shove('sqlite:///feeds.db', compress=True)
+ feed_cache = Cache(feed_storage)
+ feed = feed_cache.fetch(url)
if not (200 <= feed.status < 400):
log.warning('Got %s status from %s: %s' % (
feed.status, url, feed.headers.get('status')))
@@ -135,3 +137,7 @@ class Feed(Widget):
else:
for entry in self.iterentries(d):
d['entries'].append(entry)
+
+ def close(self):
+ global feed_storage
+ feed_storage.close()
diff --git a/moksha/streams/demo/demostream.py b/moksha/streams/demo/demostream.py
index ab47a6b..0335362 100644
--- a/moksha/streams/demo/demostream.py
+++ b/moksha/streams/demo/demostream.py
@@ -19,7 +19,8 @@ class MokshaDemoDataStream(PollingDataStream):
n = 0
# Feed demo specific variables
- feed_entries = Feed(url='http://doggdot.us/rss').entries()
+ feed = Feed(url='http://doggdot.us/rss')
+ feed_entries = feed.entries()
i = 0
def poll(self):
@@ -74,3 +75,7 @@ class MokshaDemoDataStream(PollingDataStream):
}]
self.send_message('flot_demo', flot_data)
+
+ def stop(self):
+ self.feed.close()
+ super(MokshaDemoDataStream, self).stop()
commit 919fdb367667ab81348c07fed575aeac085d410c
Author: Luke Macken <lmacken(a)redhat.com>
Date: Mon Feb 9 17:24:35 2009 -0500
Ensure we compress our Shove cache
diff --git a/moksha/api/widgets/feed/feed.py b/moksha/api/widgets/feed/feed.py
index 864b2fe..9015575 100644
--- a/moksha/api/widgets/feed/feed.py
+++ b/moksha/api/widgets/feed/feed.py
@@ -97,7 +97,7 @@ class Feed(Widget):
# This allows us to use this object outside of WSGI requests.
global cache
if not cache:
- cache = Cache(Shove('sqlite:///feeds.db'))
+ cache = Cache(Shove('sqlite:///feeds.db', compress=True))
feed = cache.fetch(url)
if not (200 <= feed.status < 400):
log.warning('Got %s status from %s: %s' % (
commit 2c7360e6a9093d313d03964c151c6b729b0ba91b
Author: Luke Macken <lmacken(a)redhat.com>
Date: Mon Feb 9 17:23:54 2009 -0500
Properly close the hub in the datastream
diff --git a/moksha/api/streams/datastream.py b/moksha/api/streams/datastream.py
index ddd4577..5b476f1 100644
--- a/moksha/api/streams/datastream.py
+++ b/moksha/api/streams/datastream.py
@@ -20,7 +20,7 @@ class DataStream(object):
log.error('Cannot send message: %s' % e)
def stop(self):
- self.hub.stop()
+ self.hub.close()
class PollingDataStream(DataStream):
commit 0d0fe11d50d029305077656ebdb9c760727f7425
Author: Luke Macken <lmacken(a)redhat.com>
Date: Mon Feb 9 17:10:54 2009 -0500
Document modifications. Add instructions for mounting a WSGI app
diff --git a/docs/index.rst b/docs/index.rst
index 6fb323c..e41ef10 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -78,8 +78,8 @@ Widgets
main/MokshaModel
-Middleware
-----------
+WSGI Middleware
+---------------
.. toctree::
:maxdepth: 1
diff --git a/docs/main/Feeds.rst b/docs/main/Feeds.rst
index 7c580a1..ccbe062 100644
--- a/docs/main/Feeds.rst
+++ b/docs/main/Feeds.rst
@@ -1,3 +1,4 @@
+=====
Feeds
=====
diff --git a/docs/main/MokshaApplications.rst b/docs/main/MokshaApplications.rst
index 70d2d7e..d6aa089 100644
--- a/docs/main/MokshaApplications.rst
+++ b/docs/main/MokshaApplications.rst
@@ -1,43 +1,45 @@
-Moksha Applications
-===================
+Moksha Plugins
+==============
-Creating a moksha application is a as easy as creating a new ToscaWidget or
-TurboGears2/Pylons project.
-
-Moksha entry points
--------------------
+When the :class:`moksha.middleware.MokshaMiddleware` is loaded, it will
+automatically load all applications and widgets from those entry points,
+and store them in ``moksha.apps`` and ``moksha._widgets`` dictionaries.
+These can then be accessed at any time by any application or widget during
+any request.
-Moksha loads all applications and widgets from the ``moksha.application`` and
-``moksha.widget`` setuptools entry point. This allows for dynamic discovery
-of moksha applications just by pointing to your Root Controller, or ToscaWidget
-in your project's `setup.py`.
+Mounting an existing WSGI application
+-------------------------------------
-Here is an example of a bare-bones setup.py, and how to integrate it with
-Moksha.
+You can mount an existing WSGI application by pointing to it
+in the ``setup.py`` on the ``[moksha.wsgiapp]`` entry-point.
.. code-block:: python
- from setuptools import setup
+ [moksha.wsgiapp]
+ mywsgiapp = mywsgiapp.wsgiapp:MyWSGIApplication
- setup(
- name='myproject',
- entry_points="""
+Your WSGI application will then be accessable via ``/appz/mywsgiapp`` in Moksha.
- [moksha.widget]
- mywidget = myproject.mywidgets:MyWidget
+Using an existing TurboGears application
+-------------------------------------------
- [moksha.application]
- myapp = myproject.controllers.root:RootController
+You can easily mount TurboGears Controllers within Moksha by pointing to them in
+your ``setup.py`` under the ``[moksha.application]`` entry-point.
- """
- )
+.. code-block:: python
+ [moksha.application]
+ myapp = myapplication.controllers.root:RootController
-When the :class:`moksha.middleware.MokshaMiddleware` is loaded, it will
-automatically load all applications and widgets from those entry points,
-and store them in ``moksha.apps`` and ``moksha._widgets`` dictionaries.
-These can then be accessed at any time by any application or widget during
-any request.
+Installing a ToscaWidget
+------------------------
+
+You can plug an existing ToscaWidget into Moksha by adding it to the ``[moksha.widget]`` entry-point.
+
+.. code-block:: python
+
+ [moksha.widget]
+ jquery = tw.jquery:jquery_js
Configuration
-------------
commit a906f7171fc9c27635cbdac528849a06bc850ab1
Author: Luke Macken <lmacken(a)redhat.com>
Date: Mon Feb 9 17:10:22 2009 -0500
Properly close our feed_storage upon shutdown, so entries can be flushed
diff --git a/moksha/__init__.py b/moksha/__init__.py
index 42bcb69..c3b5e92 100644
--- a/moksha/__init__.py
+++ b/moksha/__init__.py
@@ -23,12 +23,9 @@ menus = None
stomp = StackedObjectProxy()
def get_widget(name):
- """ Get a widget by name.
-
- This method returns a dictionary in the following format:
-
- { 'name': 'widgetname',
- 'widget': <Widget instance>,
- 'path': '/path/to/widget' }
- """
+ """ Get a widget instance by name """
return _widgets[name]['widget']
+
+def shutdown():
+ """ Called when Moksha shuts down """
+ feed_storage.close()
diff --git a/moksha/config/app_cfg.py b/moksha/config/app_cfg.py
index 964909c..c4fd658 100644
--- a/moksha/config/app_cfg.py
+++ b/moksha/config/app_cfg.py
@@ -40,3 +40,6 @@ base_config.profile = False
# Enable repoze.squeeze resource squeezing middleware
base_config.squeeze = False
+
+from moksha import shutdown
+base_config.call_on_shutdown.append(shutdown)
commit 56c31ca004ea32ce3c630a468837cb74e873bea3
Author: Luke Macken <lmacken(a)redhat.com>
Date: Mon Feb 9 17:08:46 2009 -0500
Put our feed_storage in moksha.__init__.py, and pass it the compress argument
diff --git a/moksha/__init__.py b/moksha/__init__.py
index 32da334..42bcb69 100644
--- a/moksha/__init__.py
+++ b/moksha/__init__.py
@@ -4,6 +4,9 @@ from paste.registry import StackedObjectProxy
# The central feed cache, used by the Feed widget.
feed_cache = None
+# A dict-like persistent backing store
+feed_storage = None
+
# All loaded moksha applications
apps = None
diff --git a/moksha/middleware/middleware.py b/moksha/middleware/middleware.py
index d360762..156a7ba 100644
--- a/moksha/middleware/middleware.py
+++ b/moksha/middleware/middleware.py
@@ -68,8 +68,8 @@ class MokshaMiddleware(object):
self.load_models()
self.load_menus()
- self.feed_storage = Shove(config['feed_cache'])
- moksha.feed_cache = Cache(self.feed_storage)
+ moksha.feed_storage = Shove(config['feed_cache'], compress=True)
+ moksha.feed_cache = Cache(moksha.feed_storage)
def __call__(self, environ, start_response):
self.register_stomp(environ)
commit 48bf8c5d4ee63098dacc2fd32886e2a39d9bec38
Author: Luke Macken <lmacken(a)redhat.com>
Date: Mon Feb 9 17:07:49 2009 -0500
Utilize the same feed cache as our Feed object does if the middleware isn't available
diff --git a/development.ini b/development.ini
index f925940..2c41abb 100644
--- a/development.ini
+++ b/development.ini
@@ -19,7 +19,7 @@ error_email_from = paste@localhost
##
# Where to store the feed caches.
-feed_cache = sqlite:///%(here)s/feeds.sqlite
+feed_cache = sqlite:///%(here)s/feeds.db
#feed_cache = %(here)s/data/feeds
# Where to initialize and store our application databases. %s is the app name.
commit 12d761635a2e0f2600c864ca490a47c39961261e
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 19:54:40 2009 -0500
This issue seemed to resolve itself when I moved my production deployment from paster to mod_wsgi
diff --git a/moksha/api/menus/widgets.py b/moksha/api/menus/widgets.py
index 48db2e9..b776095 100644
--- a/moksha/api/menus/widgets.py
+++ b/moksha/api/menus/widgets.py
@@ -113,8 +113,6 @@ class MokshaContextualMenu(MokshaMenuBase):
menus.append((menu.lower().replace(' ', ''), menu))
d.menus = menus
- # @@: this yields $("document") on python 2.4... we may need to
- # do this stuff in the template... or can we pass JSSource to add_call?
self.add_call(jQuery(js_callback('document')).buildContextualMenu({
'template': d.callback,
'menuWidth': d.menuWidth,
commit bff6894dbc3e71a868d4efa1af4b87f547c2f23f
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 19:51:59 2009 -0500
Open fedora menu links in new windows
diff --git a/moksha/api/menus/default.py b/moksha/api/menus/default.py
index 14ecd33..356e692 100644
--- a/moksha/api/menus/default.py
+++ b/moksha/api/menus/default.py
@@ -91,5 +91,5 @@ class MokshaDefaultMenu(MokshaMenu):
<a rel="separator"></a>
"""
for title, url in links.items():
- menu += '<a href="%s">%s</a>' % (url, title)
+ menu += '<a href="%s" target="_blank">%s</a>' % (url, title)
return menu
commit 5c0baf3eef935b03857c6a940f47c4c8abbe8c1b
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 19:47:17 2009 -0500
Use the select reactor in Orbited to begin with, so we can work out of the box on Macs.
Ideally, we should be using the kqueue reactor on Darwin, but I have no had any luck
getting it working. If someone can do it, please do so.
diff --git a/orbited.cfg b/orbited.cfg
index 6006d84..9c72ef8 100644
--- a/orbited.cfg
+++ b/orbited.cfg
@@ -14,8 +14,8 @@ stomp://:61613
# Enables the use of the proxy through the Orbited.TCPSocket JavaScript object.
proxy.enabled = 1
-reactor=epoll # Linux
-#reactor=select # Windows
+reactor=select # All platforms
+#reactor=epoll # Linux
#reactor=kqueue # OS X/FreeBSD
#session.ping_interval = 30
15 years, 4 months
start-moksha
by Luke Macken
start-moksha | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit bbe5148a53aa418a2bdc87cd8a579a0185c6eda2
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 18:15:55 2009 -0500
Install the latest tw.jquery from hg last, so it doesn't get overwritten
diff --git a/start-moksha b/start-moksha
index d1cb1c6..79ece4c 100755
--- a/start-moksha
+++ b/start-moksha
@@ -9,8 +9,8 @@ if [ ! $VIRTUAL_ENV ]; then
source tg2env/bin/activate
easy_install -U WebOb
easy_install -i http://www.turbogears.org/2.0/downloads/current/index tg.devtools
- easy_install "tw.jquery==dev"
pushd moksha/widgetbrowser; python setup.py develop; popd
+ easy_install "tw.jquery==dev"
else
source tg2env/bin/activate
fi
15 years, 4 months
5 commits - docs/main moksha/api moksha/controllers moksha/__init__.py moksha/middleware setup.py
by Luke Macken
docs/main/GlobalResources.rst | 12 ++++++----
docs/main/Middleware.rst | 2 -
moksha/__init__.py | 3 ++
moksha/api/widgets/placeholder.py | 1
moksha/controllers/apps.py | 3 +-
moksha/controllers/root.py | 23 ++-----------------
moksha/controllers/widgets.py | 44 ++++++++++++++++++++++++++++++++++++++
moksha/middleware/middleware.py | 27 +++++++++++++++++++++--
setup.py | 4 +++
9 files changed, 91 insertions(+), 28 deletions(-)
New commits:
commit e2ecd3148657e19d332c588468292bc3c8e077d7
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 17:33:43 2009 -0500
Fix up some missing modules in our new widgets controller, and do some other minor tweaks
diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py
index d9ebd48..90dc1a9 100644
--- a/moksha/controllers/root.py
+++ b/moksha/controllers/root.py
@@ -34,9 +34,6 @@ from moksha.controllers.apps import AppController
from moksha.controllers.widgets import WidgetController
#from moksha.controllers.secc import AdminController
-from moksha.widgets.container import MokshaContainer
-container = MokshaContainer('moksha_container')
-
# So we can mount the WidgetBrowser as /docs
import os
os.environ['TW_BROWSER_PREFIX'] = '/docs'
@@ -60,7 +57,7 @@ class RootController(BaseController):
def index(self):
tmpl_context.menu_widget = moksha.menus['default_menu']
tmpl_context.contextual_menu_widget = moksha.menus['contextual_menu']
- return dict(title='Moksha')
+ return dict(title='[ Moksha ]')
@expose('moksha.templates.login')
def login(self, **kw):
diff --git a/moksha/controllers/widgets.py b/moksha/controllers/widgets.py
index eecc95f..d6db65a 100644
--- a/moksha/controllers/widgets.py
+++ b/moksha/controllers/widgets.py
@@ -16,8 +16,14 @@
# Copyright 2008, Red Hat, Inc.
# Authors: Luke Macken <lmacken(a)redhat.com>
-from tg import expose
+import moksha
+
+from tg import expose, tmpl_context
+
from moksha.lib.base import Controller
+from moksha.widgets.container import MokshaContainer
+
+container = MokshaContainer('moksha_container')
class WidgetController(Controller):
diff --git a/moksha/middleware/middleware.py b/moksha/middleware/middleware.py
index 51b8406..d360762 100644
--- a/moksha/middleware/middleware.py
+++ b/moksha/middleware/middleware.py
@@ -74,7 +74,8 @@ class MokshaMiddleware(object):
def __call__(self, environ, start_response):
self.register_stomp(environ)
request = Request(environ)
- if request.path.startswith('/appz'):
+ if request.path.startswith('/appz/') or request.path.startswith('/widget') or \
+ request.path.startswith('/docs/'):
response = request.get_response(self.mokshaapp)
else:
response = request.get_response(self.application)
commit 4a6c7cc248ec29a11e46e48446176b7ab70da3a3
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 17:30:19 2009 -0500
Hide the placeholder widget from our widgets menu
diff --git a/moksha/api/widgets/placeholder.py b/moksha/api/widgets/placeholder.py
index 656580e..61b3dd8 100644
--- a/moksha/api/widgets/placeholder.py
+++ b/moksha/api/widgets/placeholder.py
@@ -2,6 +2,7 @@ from tw.api import Widget
class Placeholder(Widget):
engine_name = 'mako'
+ hidden = True
template = """
<div class='placeholder'>
Moksha application <strong>${appname}</strong> is not registered yet. This is a placeholder
commit 174aa74031d58926e715c00ea9a37f6507fa4ab0
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 17:22:42 2009 -0500
Add the ability to plugin and mount WSGI applications.
The MokshaMiddleware loads all WSGI Applications from the `moksha.wsgiapps` entry-point,
wraps them in the tg.WSGIAppController, and stores them in the moksha.apps dictionary.
This allows us to freely dispatch between TG apps and WSGI applications using the
same lookup/dispatch controller.
diff --git a/docs/main/Middleware.rst b/docs/main/Middleware.rst
index 5dc27d8..93f9258 100644
--- a/docs/main/Middleware.rst
+++ b/docs/main/Middleware.rst
@@ -9,7 +9,7 @@ application with a lot of additional functionality as well. This allows you to
It currently provides the following functionality
* Sets up the feed storage and cache for widgets
- * Handles dispatching moksha applications, which can be any WSGI app
+ * Handles dispatching moksha applications, which can be any WSGI app or Controller.
* Handles dispatching to individual widgets, which are simply `ToscaWidgets <http://toscawidgets.org>`_
* Sets up `SQLAlchemy` database engines for each application
* Initializes applications data models
diff --git a/moksha/__init__.py b/moksha/__init__.py
index e34a9dd..32da334 100644
--- a/moksha/__init__.py
+++ b/moksha/__init__.py
@@ -7,6 +7,9 @@ feed_cache = None
# All loaded moksha applications
apps = None
+# All WSGI applications
+wsgiapps = None
+
# All loaded ToscaWidgets
_widgets = None
diff --git a/moksha/controllers/apps.py b/moksha/controllers/apps.py
index ee0e58e..cdbf029 100644
--- a/moksha/controllers/apps.py
+++ b/moksha/controllers/apps.py
@@ -20,11 +20,12 @@ import moksha
from tg import expose
from moksha.lib.base import Controller
+from moksha.exc import ApplicationNotFound
class AppController(Controller):
@expose()
def lookup(self, app, *remainder):
if app not in moksha.apps:
- raise AppNotFoundException(app)
+ raise ApplicationNotFound(app)
return moksha.apps[app]['controller'], remainder
diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py
index b3edfbf..d9ebd48 100644
--- a/moksha/controllers/root.py
+++ b/moksha/controllers/root.py
@@ -41,7 +41,6 @@ container = MokshaContainer('moksha_container')
import os
os.environ['TW_BROWSER_PREFIX'] = '/docs'
-
class RootController(BaseController):
appz = AppController()
diff --git a/moksha/middleware/middleware.py b/moksha/middleware/middleware.py
index 4d06161..51b8406 100644
--- a/moksha/middleware/middleware.py
+++ b/moksha/middleware/middleware.py
@@ -23,6 +23,7 @@ import pkg_resources
import simplejson as json
import urllib
+from tg.controllers import WSGIAppController
from webob import Request, Response
from shove import Shove
from pylons import config
@@ -53,7 +54,7 @@ class MokshaMiddleware(object):
self.application = application
self.mokshaapp = MokshaAppDispatcher()
- moksha.apps = {} # {'app name': tg.TGController}
+ moksha.apps = {} # {'app name': tg.TGController/tg.WSGIAppController}
moksha._widgets = {} # {'widget name': tw.api.Widget}
moksha.menus = {} # {'menu name': moksha.api.menus.MokshaMenu}
self.engines = {} # {'app name': sqlalchemy.engine.base.Engine}
@@ -63,6 +64,7 @@ class MokshaMiddleware(object):
self.load_configs()
self.load_widgets()
self.load_applications()
+ self.load_wsgi_applications()
self.load_models()
self.load_menus()
@@ -134,6 +136,26 @@ class MokshaMiddleware(object):
except ImportError:
pass
+ def load_wsgi_applications(self):
+ log.info('Loading moksha WSGI applications')
+ for app_entry in pkg_resources.iter_entry_points('moksha.wsgiapp'):
+ log.info('Loading %s WSGI application' % app_entry.name)
+ app_class = app_entry.load()
+ app_path = app_entry.dist.location
+ moksha.apps[app_entry.name] = {
+ 'name': getattr(app_class, 'name', app_entry.name),
+ 'controller': WSGIAppController(app_class()),
+ 'path': app_path,
+ 'model': None,
+ }
+ try:
+ model = __import__('%s.model' % app_entry.name,
+ globals(), locals(),
+ [app_entry.name])
+ moksha.apps[app_entry.name]['model'] = model
+ except ImportError:
+ pass
+
def load_widgets(self):
log.info('Loading moksha widgets')
for widget_entry in pkg_resources.iter_entry_points('moksha.widget'):
diff --git a/setup.py b/setup.py
index c1340c3..7aa603d 100644
--- a/setup.py
+++ b/setup.py
@@ -56,6 +56,10 @@ setup(
#[moksha.consumer]
#moksha = moksha.hub.hub:MokshaConsumer
+ #[moksha.wsgiapp]
+ # Use this entry point to mount WSGI applications, which can then be accessed
+ # the same as regular apps, through the `/appz/name` url.
+
[moksha.application]
menu = moksha.api.menus.controllers:MokshaMenuController
chat = moksha.api.widgets.chat.controllers:ChatController
commit 5c44e0ea4a2c27c94e6c0295f58fec7fcb192d89
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 15:36:41 2009 -0500
Update some of the entrypoints in our GlobalResource docs
diff --git a/docs/main/GlobalResources.rst b/docs/main/GlobalResources.rst
index d8b0096..8d0c49d 100644
--- a/docs/main/GlobalResources.rst
+++ b/docs/main/GlobalResources.rst
@@ -4,7 +4,7 @@ Global Resource Injection
Moksha has plugin suport for `Global Resources`, which are just JavaScript or
CSS widgets that will get automatically injected in every page by the
-:class:`GlobalResourceInjectionWidget`
+:class:`GlobalResourceInjectionWidget`.
Moksha will load all `JSLink
<http://toscawidgets.org/documentation/ToscaWidgets/modules/api.html#jslink>`_,
@@ -24,10 +24,14 @@ Here is an example of what some global resources look like in Moksha's `setup.py
[moksha.global]
jquery = tw.jquery:jquery_js
- jquery_ui_core = moksha.widgets.container:ui_core_js
- jquery_ui_draggable = moksha.widgets.container:ui_draggable_js
- jquery_ui_resizable = moksha.widgets.container:ui_resizable_js
+ jquery_ui_core = tw.jquery.ui:ui_core_js
+ jquery_ui_draggable = tw.jquery.ui:ui_draggable_min_js
+ jquery_ui_resizable = tw.jquery.ui:ui_resizable_min_js
+ jquery_ui_dialog = tw.jquery.ui:ui_dialog_min_js
+ jquery_ui_tabs = tw.jquery.ui_tabs:jquery_ui_tabs_js
+ # Enable support for the Blueprint CSS framework & Plugins
blueprint_ie_css = moksha.widgets.blueprint:blueprint_ie_css
blueprint_screen_css = moksha.widgets.blueprint:blueprint_screen_css
blueprint_print_css = moksha.widgets.blueprint:blueprint_print_css
+ blueprint_fancytype_css = moksha.widgets.blueprint:blueprint_plugin_fancytype_css
commit 39f9402282352643ce3a4995f82e11ee9998c364
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 15:25:44 2009 -0500
Pull the widgets method out into it's own WidgetController
diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py
index 8d3bbb8..b3edfbf 100644
--- a/moksha/controllers/root.py
+++ b/moksha/controllers/root.py
@@ -31,6 +31,7 @@ from moksha.lib.base import BaseController
from moksha.exc import ApplicationNotFound
from moksha.controllers.error import ErrorController
from moksha.controllers.apps import AppController
+from moksha.controllers.widgets import WidgetController
#from moksha.controllers.secc import AdminController
from moksha.widgets.container import MokshaContainer
@@ -40,9 +41,11 @@ container = MokshaContainer('moksha_container')
import os
os.environ['TW_BROWSER_PREFIX'] = '/docs'
+
class RootController(BaseController):
appz = AppController()
+ widgets = WidgetController()
error = ErrorController()
#admin = AdminController()
@@ -60,22 +63,6 @@ class RootController(BaseController):
tmpl_context.contextual_menu_widget = moksha.menus['contextual_menu']
return dict(title='Moksha')
- @expose('mako:moksha.templates.widget')
- def widgets(self, widget, chrome=None, **kw):
- options = {}
- options.update(kw)
- w = moksha._widgets.get(widget)
- if not w:
- raise WidgetNotFound(widget)
- if chrome and getattr(w['widget'], 'visible', True):
- tmpl_context.widget = container
- options['content'] = w['widget']
- options['title'] = w['name']
- options['id'] = widget + '_container'
- else:
- tmpl_context.widget = w['widget']
- return dict(options=options)
-
@expose('moksha.templates.login')
def login(self, **kw):
came_from = kw.get('came_from', '/')
diff --git a/moksha/controllers/widgets.py b/moksha/controllers/widgets.py
new file mode 100644
index 0000000..eecc95f
--- /dev/null
+++ b/moksha/controllers/widgets.py
@@ -0,0 +1,38 @@
+# This file is part of Moksha.
+#
+# Moksha is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Moksha is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Moksha. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2008, Red Hat, Inc.
+# Authors: Luke Macken <lmacken(a)redhat.com>
+
+from tg import expose
+from moksha.lib.base import Controller
+
+class WidgetController(Controller):
+
+ @expose('mako:moksha.templates.widget')
+ def default(self, widget, chrome=None, **kw):
+ options = {}
+ options.update(kw)
+ w = moksha._widgets.get(widget)
+ if not w:
+ raise WidgetNotFound(widget)
+ if chrome and getattr(w['widget'], 'visible', True):
+ tmpl_context.widget = container
+ options['content'] = w['widget']
+ options['title'] = w['name']
+ options['id'] = widget + '_container'
+ else:
+ tmpl_context.widget = w['widget']
+ return dict(options=options)
15 years, 4 months
moksha/controllers
by Luke Macken
moksha/controllers/apps.py | 1 -
1 file changed, 1 deletion(-)
New commits:
commit 56674e8bf3ba1b93455ea7f2e31d36b9c9216bfa
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 03:26:34 2009 -0500
Remove unnecessary print statement
diff --git a/moksha/controllers/apps.py b/moksha/controllers/apps.py
index 1b92be9..ee0e58e 100644
--- a/moksha/controllers/apps.py
+++ b/moksha/controllers/apps.py
@@ -25,7 +25,6 @@ class AppController(Controller):
@expose()
def lookup(self, app, *remainder):
- print locals()
if app not in moksha.apps:
raise AppNotFoundException(app)
return moksha.apps[app]['controller'], remainder
15 years, 4 months
4 commits - docs/main moksha/api moksha/controllers moksha/lib moksha/widgetbrowser
by Luke Macken
docs/main/GettingStarted.rst | 2 +-
moksha/api/menus/default.py | 8 +++-----
moksha/controllers/root.py | 14 ++++++++------
moksha/lib/base.py | 4 +++-
moksha/widgetbrowser/widgetbrowser/wsgiapp.py | 6 ++++++
5 files changed, 21 insertions(+), 13 deletions(-)
New commits:
commit 5bcfac34a2b60b28cf17479aaa637a233988bdcf
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 03:19:07 2009 -0500
Inject moksha's global resources into widget demos
diff --git a/moksha/widgetbrowser/widgetbrowser/wsgiapp.py b/moksha/widgetbrowser/widgetbrowser/wsgiapp.py
index 266a826..600d8b2 100644
--- a/moksha/widgetbrowser/widgetbrowser/wsgiapp.py
+++ b/moksha/widgetbrowser/widgetbrowser/wsgiapp.py
@@ -218,6 +218,12 @@ class WidgetBrowser(object):
widget_output = util.display_widget(widget, _disp, self.context)
if not callable(widget_output):
widget_output = Markup(widget_output)
+
+ # Inject moksha's global resources so we can get things like
+ # Orbited/Stomp/jQuery/etc.
+ from moksha.api.widgets.global_resources import global_resources
+ global_resources.register_resources()
+
return self.render('show_widget.html', locals())
def widgets(self, req, resp):
commit 07ccbcb484d9e90971e59719df609091324fcece
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 03:18:16 2009 -0500
Mount the ToscaWidgets WidgetBrowser at /docs
diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py
index 2938dc1..8d3bbb8 100644
--- a/moksha/controllers/root.py
+++ b/moksha/controllers/root.py
@@ -36,8 +36,9 @@ from moksha.controllers.apps import AppController
from moksha.widgets.container import MokshaContainer
container = MokshaContainer('moksha_container')
-#import os
-#os.putenv('TW_BROWSER_PREFIX', '/docs')
+# So we can mount the WidgetBrowser as /docs
+import os
+os.environ['TW_BROWSER_PREFIX'] = '/docs'
class RootController(BaseController):
@@ -46,11 +47,12 @@ class RootController(BaseController):
#admin = AdminController()
# ToscaWidgets WidgetBrowser integration
- widget = WSGIAppController(
+ docs = WSGIAppController(
WidgetBrowser(
- template_dirs=[resource_filename('moksha','templates/widget_browser')],
- full_stack=False,
- docs_dir=config.get('docs_dir', 'docs')))
+ template_dirs=[
+ resource_filename('moksha','templates/widget_browser')],
+ docs_dir=config.get('docs_dir', 'docs'),
+ full_stack=False))
@expose('mako:moksha.templates.index')
def index(self):
diff --git a/moksha/lib/base.py b/moksha/lib/base.py
index 8332c1d..7d77a1b 100644
--- a/moksha/lib/base.py
+++ b/moksha/lib/base.py
@@ -44,7 +44,9 @@ class BaseController(TGController):
tmpl_context.get_url = url
## Inject our global resources
- if request.path.startswith('/appz') or request.path.startswith('/widgets'):
+ if request.path.startswith('/appz') or \
+ request.path.startswith('/widgets') or \
+ request.path.startswith('/docs'):
# Don't inject global resources for apps or widgets.
tmpl_context.moksha_global_resources = lambda: ''
else:
commit ed8ae155b4fc7f190d9497ae45163c2c8a1b61e8
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 03:17:28 2009 -0500
Link to our internal live sphinx documentation in our menus
diff --git a/moksha/api/menus/default.py b/moksha/api/menus/default.py
index e7e0628..14ecd33 100644
--- a/moksha/api/menus/default.py
+++ b/moksha/api/menus/default.py
@@ -26,15 +26,14 @@ class MokshaContextMenu(MokshaContextualMenu):
<a rel="text">
<img src="/images/moksha-icon.png" style="position:absolute;margin-top:-20px; margin-left:-25px;margin-bottom:10px"/><br/>
</a>
- <a href="http://moksha.fedorahosted.org" target="_blank">Moksha Homepage</a>
<a href="/widget">Documentation</a>
<a href="https://fedorahosted.org/moksha/report/3">Tickets</a>
<a href="https://fedorahosted.org/moksha/">Wiki</a>
"""
-
class MokshaDefaultMenu(MokshaMenu):
- menus = ['Moksha', 'Applications', 'Widgets', 'Fedora']
+ menus = ['Moksha', 'Widgets', 'Fedora']
+ #menus = ['Moksha', 'Applications', 'Widgets', 'Fedora']
def applications(self, *args, **kw):
menu = """
@@ -67,8 +66,7 @@ class MokshaDefaultMenu(MokshaMenu):
<br>Moksha is a platform for creating live collaborative web applications.<br><br>
</a>
<a rel="separator"></a>
- <a href="http://moksha.fedorahosted.org" target="_blank">Moksha Homepage</a>
- <a href="/widget">Documentation</a>
+ <a href="/docs/">Documentation</a>
<a href="https://fedorahosted.org/moksha/report/3">Tickets</a>
<a href="https://fedorahosted.org/moksha/">Wiki</a>
"""
commit c7b73b8291c25c2eb0b9d51e1c3e509307dcc606
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 03:04:32 2009 -0500
For some reason we need pysvn and mercurial now :(
diff --git a/docs/main/GettingStarted.rst b/docs/main/GettingStarted.rst
index 8ed2247..7fc7774 100644
--- a/docs/main/GettingStarted.rst
+++ b/docs/main/GettingStarted.rst
@@ -24,7 +24,7 @@ You'll need the `virtualenv <http://pypi.python.org/pypi/virtualenv>`_ package.
.. code-block:: bash
- # yum -y install python-virtualenv
+ # yum -y install python-virtualenv pysvn mercurial
The `start-moksha` script mentioned below should install all of the necessary
dependencies. However, it will attempt to compile a few things, such as lxml. So, you may need to install some additional dependencies like `libxml2` and `libxslt` in order to build it. If you're using yum, you can easily install all of the build requirements by doing:
15 years, 4 months
start-moksha
by Luke Macken
start-moksha | 1 +
1 file changed, 1 insertion(+)
New commits:
commit 5ea8542eda568164aab9d769aebef6aa371d0788
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 02:28:18 2009 -0500
Mitigate more setuptools fail
diff --git a/start-moksha b/start-moksha
index 166f494..d1cb1c6 100755
--- a/start-moksha
+++ b/start-moksha
@@ -7,6 +7,7 @@ if [ ! $VIRTUAL_ENV ]; then
virtualenv --no-site-packages tg2env
#virtualenv tg2env
source tg2env/bin/activate
+ easy_install -U WebOb
easy_install -i http://www.turbogears.org/2.0/downloads/current/index tg.devtools
easy_install "tw.jquery==dev"
pushd moksha/widgetbrowser; python setup.py develop; popd
15 years, 4 months
2 commits - moksha/controllers start-moksha
by Luke Macken
moksha/controllers/apps.py | 31 +++++++++++++++++++++++++++++++
moksha/controllers/root.py | 14 ++++----------
start-moksha | 1 -
3 files changed, 35 insertions(+), 11 deletions(-)
New commits:
commit 4a2cc2c80696c07b558fdc87e4c2d237226bfd6c
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 02:05:51 2009 -0500
App the app lookup method out into it's own controller.
diff --git a/moksha/controllers/apps.py b/moksha/controllers/apps.py
new file mode 100644
index 0000000..1b92be9
--- /dev/null
+++ b/moksha/controllers/apps.py
@@ -0,0 +1,31 @@
+# This file is part of Moksha.
+#
+# Moksha is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Moksha is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Moksha. If not, see <http://www.gnu.org/licenses/>.
+#
+# Copyright 2008, Red Hat, Inc.
+# Authors: Luke Macken <lmacken(a)redhat.com>
+
+import moksha
+
+from tg import expose
+from moksha.lib.base import Controller
+
+class AppController(Controller):
+
+ @expose()
+ def lookup(self, app, *remainder):
+ print locals()
+ if app not in moksha.apps:
+ raise AppNotFoundException(app)
+ return moksha.apps[app]['controller'], remainder
diff --git a/moksha/controllers/root.py b/moksha/controllers/root.py
index a626260..2938dc1 100644
--- a/moksha/controllers/root.py
+++ b/moksha/controllers/root.py
@@ -28,9 +28,10 @@ from widgetbrowser import WidgetBrowser
from moksha import _
from moksha.model import DBSession
from moksha.lib.base import BaseController
-#from moksha.controllers.secc import AdminController
from moksha.exc import ApplicationNotFound
from moksha.controllers.error import ErrorController
+from moksha.controllers.apps import AppController
+#from moksha.controllers.secc import AdminController
from moksha.widgets.container import MokshaContainer
container = MokshaContainer('moksha_container')
@@ -40,8 +41,9 @@ container = MokshaContainer('moksha_container')
class RootController(BaseController):
- #admin = AdminController()
+ appz = AppController()
error = ErrorController()
+ #admin = AdminController()
# ToscaWidgets WidgetBrowser integration
widget = WSGIAppController(
@@ -50,14 +52,6 @@ class RootController(BaseController):
full_stack=False,
docs_dir=config.get('docs_dir', 'docs')))
- @expose()
- def lookup(self, resource, *remainder):
- if resource == 'appz':
- app = remainder[0]
- if app not in moksha.apps:
- raise AppNotFoundException(app)
- return moksha.apps[app]['controller'], remainder[1:]
-
@expose('mako:moksha.templates.index')
def index(self):
tmpl_context.menu_widget = moksha.menus['default_menu']
commit 43604fa09cf3ea5d4d3afa53d6a70fb5bdf0818b
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 01:50:01 2009 -0500
Remove obsolete TG2 b5 link
diff --git a/start-moksha b/start-moksha
index 78b8e32..166f494 100755
--- a/start-moksha
+++ b/start-moksha
@@ -7,7 +7,6 @@ if [ ! $VIRTUAL_ENV ]; then
virtualenv --no-site-packages tg2env
#virtualenv tg2env
source tg2env/bin/activate
- #easy_install -i http://www.turbogears.org/2.0/downloads/2.0b5/index tg.devtools
easy_install -i http://www.turbogears.org/2.0/downloads/current/index tg.devtools
easy_install "tw.jquery==dev"
pushd moksha/widgetbrowser; python setup.py develop; popd
15 years, 4 months
moksha/wsgiapp.py
by Luke Macken
moksha/wsgiapp.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
New commits:
commit d92129d154f1d9788bda5fc8357484d03cbf6cac
Author: Luke Macken <lmacken(a)redhat.com>
Date: Fri Feb 6 00:45:44 2009 -0500
Don't import the Moksha root controller until our tg.config is parsed and loaded
diff --git a/moksha/wsgiapp.py b/moksha/wsgiapp.py
index 6d74781..5003877 100644
--- a/moksha/wsgiapp.py
+++ b/moksha/wsgiapp.py
@@ -19,7 +19,6 @@
from pylons.wsgiapp import PylonsApp
import moksha
-from moksha.controllers.root import RootController
class MokshaAppDispatcher(PylonsApp):
""" Moksha WSGI Application Dispatcher.
@@ -30,6 +29,7 @@ class MokshaAppDispatcher(PylonsApp):
"""
def __init__(self, *args, **kw):
super(MokshaAppDispatcher, self).__init__(*args, **kw)
+ from moksha.controllers.root import RootController
self.root = RootController()
def resolve(self, environ, start_response):
15 years, 4 months