Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of github.com:pusewicz/sonia

  • Loading branch information...
commit 7f5515d3f87a5ff12991aad6306d9f659a04a989 2 parents 04ca935 + b04951c
Piotr Usewicz authored
Showing with 4,735 additions and 54 deletions.
  1. +3 −3 Gemfile
  2. +11 −11 lib/sonia/helpers.rb
  3. BIN  public/images/icons/button_blue_add.png
  4. +1 −12 public/javascripts/dispatcher.js
  5. +123 −0 public/javascripts/pager.js
  6. +23 −0 public/javascripts/sonia.js
  7. +29 −3 public/javascripts/widget.js
  8. +35 −9 public/stylesheets/sonia.css
  9. 0  public/{javascripts → vendor}/FABridge.js
  10. 0  public/{javascripts → vendor}/builder.js
  11. 0  public/{javascripts → vendor}/contextmenu.js
  12. 0  public/{javascripts → vendor}/controls.js
  13. 0  public/{javascripts → vendor}/cookie.js
  14. 0  public/{javascripts → vendor}/dragdrop.js
  15. 0  public/{javascripts → vendor}/effects.js
  16. 0  public/{javascripts → vendor}/event_behavior.js
  17. 0  public/{javascripts → vendor}/hotkey.js
  18. 0  public/{javascripts → vendor}/json2.js
  19. 0  public/{javascripts → vendor}/livepipe.js
  20. 0  public/{javascripts → vendor}/progressbar.js
  21. 0  public/{javascripts → vendor}/prototype.js
  22. 0  public/{javascripts → vendor}/rating.js
  23. 0  public/{javascripts → vendor}/resizable.js
  24. +4,410 −0 public/vendor/s2.js
  25. 0  public/{javascripts → vendor}/scrollbar.js
  26. 0  public/{javascripts → vendor}/selection.js
  27. 0  public/{javascripts → vendor}/selectmultiple.js
  28. 0  public/{javascripts → vendor}/slider.js
  29. 0  public/{javascripts → vendor}/sound.js
  30. 0  public/{javascripts → vendor}/swfobject.js
  31. 0  public/{javascripts → vendor}/tabs.js
  32. 0  public/{javascripts → vendor}/textarea.js
  33. 0  public/{javascripts → vendor}/unittest.js
  34. 0  public/{javascripts → vendor}/web_socket.js
  35. 0  public/{javascripts → vendor}/window.js
  36. +89 −0 spec/sonia/config_spec.rb
  37. +0 −7 spec/sonia_spec.rb
  38. +1 −0  spec/spec.opts
  39. BIN  vendor/cache/gemcutter-0.5.0.gem
  40. BIN  vendor/cache/git-1.2.5.gem
  41. BIN  vendor/cache/jeweler-1.4.0.gem
  42. BIN  vendor/cache/json_pure-1.4.3.gem
  43. BIN  vendor/cache/rspec-1.3.0.gem
  44. BIN  vendor/cache/rubyforge-2.0.4.gem
  45. BIN  vendor/cache/yard-0.5.4.gem
  46. +1 −0  views/index.haml
  47. +1 −1  widgets/campfire/campfire.js
  48. +1 −1  widgets/foursquare/foursquare.js
  49. +1 −1  widgets/github/github.js
  50. +1 −1  widgets/icinga/icinga.js
  51. +1 −1  widgets/rss/rss.js
  52. +1 −1  widgets/tfl/tfl.js
  53. +1 −1  widgets/twitter/twitter.js
  54. +1 −1  widgets/twitter/twitter.rb
  55. +1 −1  widgets/yahoo_weather/yahoo_weather.js
6 Gemfile
View
@@ -16,10 +16,10 @@ group :runtime do
gem "haml", "2.2.24"
end
-#group :test do
- #gem "rspec"
+group :test do
+ gem "rspec"
#gem "cucumber"
-#end
+end
group :development do
gem "yard"
22 lib/sonia/helpers.rb
View
@@ -22,17 +22,17 @@ def widget_stylesheets
def joined_system_javascript
files = %w(
- /javascripts/swfobject.js
- /javascripts/FABridge.js
- /javascripts/web_socket.js
- /javascripts/json2.js
- /javascripts/prototype.js
- /javascripts/effects.js
- /javascripts/dragdrop.js
- /javascripts/livepipe.js
- /javascripts/window.js
- /javascripts/resizable.js
- /javascripts/cookie.js
+ /vendor/swfobject.js
+ /vendor/FABridge.js
+ /vendor/web_socket.js
+ /vendor/json2.js
+ /vendor/prototype.js
+ /vendor/effects.js
+ /vendor/dragdrop.js
+ /vendor/livepipe.js
+ /vendor/window.js
+ /vendor/resizable.js
+ /vendor/cookie.js
/javascripts/storage.js
/javascripts/sonia.js
/javascripts/dispatcher.js
BIN  public/images/icons/button_blue_add.png
View
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 public/javascripts/dispatcher.js
View
@@ -16,18 +16,7 @@ var Dispatcher = Class.create({
console.log("Missing data in message message:", json.message);
}
} else if(json.setup) {
- var widgets = json.setup;
- widgets.each(function(payload) {
- var widget = payload.widget;
- var widget_id = payload.widget_id;
- var config = payload.config;
- if(widget && widget_id && config) {
- var widget_object = eval("new " + widget + "(widget_id, config)");
- this.sonia.addWidget(widget_id, widget_object);
- } else {
- console.log("Missing data in setup message:", json.setup);
- }
- }.bind(this));
+ this.sonia.addWidgets(json.setup);
}
}
});
123 public/javascripts/pager.js
View
@@ -0,0 +1,123 @@
+var Pager = Class.create({
+ initialize: function(sonia) {
+ this.sonia = sonia;
+ this.pages = [];
+ this.currentPage = 0;
+ this.build();
+ setInterval(this.changePage.bind(this), 60 * 100);
+ },
+
+ addWidgetToCurrentPage: function(widgetSha) {
+ if(!this.pages[this.currentPage]) {
+ this.pages[this.currentPage] = [];
+ this.pageCount = this.pages.size();
+ }
+
+ this.getCurrentPage().push(widgetSha);
+ this.update();
+ // TODO: Remove this in final version
+ if(this.getCurrentPage().size() % 3 == 0) this.currentPage++;
+ },
+
+ changePage: function() {
+ var currPage = this.currentPage;
+ if(++this.currentPage >= this.pageCount) {
+ this.currentPage = 0;
+ }
+
+ this.transitionToNewPage(currPage, this.currentPage);
+ this.update();
+ },
+
+ transitionToNewPage: function(fromIdx, toIdx) {
+ var currentPage = this.pages[fromIdx];
+ var nextPage = this.pages[toIdx];
+
+ var viewportWidth = document.viewport.getWidth();
+ // Prepare next page widgets
+
+ var nextWidgets = nextPage.collect(function(el) {
+ return this.sonia.widgets[el];
+ }, this);
+
+ var currentWidgets = currentPage.collect(function(el) {
+ return this.sonia.widgets[el];
+ }, this);
+
+ nextWidgets.each(function(w) {
+ var destX = w.x + viewportWidth;
+ var widget = $(w.widget_id);
+ console.log("Setting", widget, "to", destX);
+ widget.setStyle({left: destX + "px"});
+ console.log("Morphing next", widget, "to", w.x);
+ widget.morph("left:" + w.x + "px", {
+ duration: 0.7,
+ transition: 'easeInOutExpo',
+ propertyTransitions: {
+ top: 'spring', left: 'easeInOutCirc'
+ }
+ });
+ });
+
+ currentWidgets.each(function(w) {
+ var destX = -(w.x + viewportWidth);
+ var widget = $(w.widget_id);
+ console.log("Morphing current", widget, "to", destX);
+ widget.morph("left:" + destX + "px", {
+ duration: 0.7,
+ transition: 'easeInOutExpo',
+ propertyTransitions: {
+ top: 'spring', left: 'easeInOutCirc'
+ }
+ });
+ });
+ },
+
+ build: function() {
+ this.buildPager();
+ },
+
+ update: function() {
+ this.buildPager();
+ this.showOnlyCurrentPageWidgets();
+ },
+
+ buildPager: function() {
+ if(this.pagerContainer) { $(this.pagerContainer).remove(); }
+ this.pagerContainer = new Element("ul", { id: "pager" });
+ this.pages.each(function(page) {
+ this.pagerContainer.insert(new Element("li", { 'class': (this.getCurrentPage() == page) ? 'current' : '' }).update("•"));
+ }, this);
+ $("widgets").insert(this.pagerContainer);
+ },
+
+ showOnlyCurrentPageWidgets: function() {
+ this.currentPageWidgets().each(function(el) {
+ //$(el).show();
+ }, this);
+
+ this.notCurrentPageWidgets().each(function(el) {
+ //$(el).hide();
+ }, this);
+ },
+
+ currentPageWidgets: function() {
+ return(this.getCurrentPage().collect(function(el) {
+ return $(el);
+ }, this));
+ },
+
+ notCurrentPageWidgets: function() {
+ var nonCurrentPages = this.pages.findAll(function(el) {
+ return(el != this.getCurrentPage());
+ }, this);
+
+ return(nonCurrentPages.flatten().collect(function(el) {
+ return $(el);
+ }));
+ },
+
+ getCurrentPage: function() {
+ return(this.pages[this.currentPage]);
+ }
+});
23 public/javascripts/sonia.js
View
@@ -9,6 +9,8 @@ var Sonia = Class.create({
this.websocket.onmessage = this.onmessage.bind(this);
this.websocket.onclose = this.onclose.bind(this);
this.websocket.onerror = this.onerror.bind(this);
+
+ //this.pager = new Pager(this);
},
onopen: function() {
console.log("Socket opened... ");
@@ -24,9 +26,30 @@ var Sonia = Class.create({
onerror: function(event) {
console.log("Received error:", event);
},
+
+ getWidgets: function() {
+ return(this.widgets);
+ },
+
+ addWidgets: function(setup) {
+ setup.each(function(payload) {
+ var widget = payload.widget;
+ var widget_id = payload.widget_id;
+ var config = payload.config;
+ if(widget && widget_id && config) {
+ var widget_object = eval("new " + widget + "(widget_id, config)");
+ this.addWidget(widget_id, widget_object);
+ } else {
+ console.log("Missing data in setup message:", json.setup);
+ }
+ }.bind(this));
+ },
+
addWidget: function(widget_id, widget) {
this.widgets[widget_id] = widget;
+ //this.pager.addWidgetToCurrentPage(widget_id);
},
+
saveChanges: function() {
$H(this.widgets).each(function(pair) {
pair.value.savePosition();
32 public/javascripts/widget.js
View
@@ -4,6 +4,10 @@ var Widget = Class.create({
this.widget_id = widget_id;
this.title = config.title;
this.config = config;
+
+ this.x = 0;
+ this.y = 0;
+
this.buildContainer(config);
this.build();
this.restorePosition();
@@ -32,8 +36,11 @@ var Widget = Class.create({
},
savePosition: function() {
- var position = { left: this.container.measure("left"), top: this.container.measure("top") };
- Storage.set(this.attrKey("position"), position);
+ var left = this.container.measure("left");
+ var top = this.container.measure("top");
+ if(left >= 0 && top >= 0) {
+ Storage.set(this.attrKey("position"), { left: left, top: top });
+ }
},
restorePosition: function() {
@@ -44,11 +51,30 @@ var Widget = Class.create({
this.container.setStyle({ left: (left < 0) ? 0 : left + "px", top: (top < 0) ? 0 : top + "px"});
} catch(err) {
+ this.container.setStyle({ left: "0px", top: "0px"});
console.warn("Cound not set restore position", err);
}
+ var viewportWidth = document.viewport.getWidth();
+ if(this.container.measure("left") >= viewportWidth) {
+ this.container.setStyle({ left: "0px", top: "0px"});
+ }
+ this.setCoordinates();
+ },
+
+ setCoordinates: function() {
+ this.x = parseInt(this.container.measure("left"));
+ this.y = parseInt(this.container.measure("top"));
+ console.log("Stored coordinates", this.x, this.y);
},
attrKey: function(attr) {
return(this.widget_id + "_" + attr);
- }
+ },
+
+ makeDraggable: function() {
+ new Draggable(this.container, { onEnd: function() {
+ this.savePosition();
+ this.setCoordinates();
+ }.bindAsEventListener(this)});
+ },
});
44 public/stylesheets/sonia.css
View
@@ -1,17 +1,25 @@
+html {
+ width: 100%;
+ height: 100%;
+ margin: 0;
+ padding: 0;
+ overflow: hidden;
+}
+
body * {
cursor: default;
}
body {
- background: black; /* fallback for older/unsupporting browsers */
- background-image: -webkit-gradient(linear,
- left bottom,
- left top,
- color-stop(0.12, rgb(77,77,77)),
- color-stop(0.59, rgb(0,0,0)));
- color: white;
- font-size: 14px;
- font-family: "Optima";
+ margin: 0;
+ padding: 0;
+ width: 100%;
+ height: 100%;
+ background-color: black;
+ color: #EAEAEA;
+ font-size: 16px;
+ font-family: HelveticaNeue-Light, 'Helvetica Neue Light', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ font-weight: 300;
}
h1 {
@@ -88,3 +96,21 @@ div.widget img.icon {
top: -35px;
right: 0;
}
+
+#pager {
+ list-style-type: none;
+ list-style-position: inline;
+ width: 128px;
+ margin: 0px auto;
+ text-align: center;
+}
+
+#pager li {
+ display: inline;
+ color: #363636;
+ padding: 8px 8px;
+}
+
+#pager li.current {
+ color: #EAEAEA;
+}
0  public/javascripts/FABridge.js → public/vendor/FABridge.js
View
File renamed without changes
0  public/javascripts/builder.js → public/vendor/builder.js
View
File renamed without changes
0  public/javascripts/contextmenu.js → public/vendor/contextmenu.js
View
File renamed without changes
0  public/javascripts/controls.js → public/vendor/controls.js
View
File renamed without changes
0  public/javascripts/cookie.js → public/vendor/cookie.js
View
File renamed without changes
0  public/javascripts/dragdrop.js → public/vendor/dragdrop.js
View
File renamed without changes
0  public/javascripts/effects.js → public/vendor/effects.js
View
File renamed without changes
0  public/javascripts/event_behavior.js → public/vendor/event_behavior.js
View
File renamed without changes
0  public/javascripts/hotkey.js → public/vendor/hotkey.js
View
File renamed without changes
0  public/javascripts/json2.js → public/vendor/json2.js
View
File renamed without changes
0  public/javascripts/livepipe.js → public/vendor/livepipe.js
View
File renamed without changes
0  public/javascripts/progressbar.js → public/vendor/progressbar.js
View
File renamed without changes
0  public/javascripts/prototype.js → public/vendor/prototype.js
View
File renamed without changes
0  public/javascripts/rating.js → public/vendor/rating.js
View
File renamed without changes
0  public/javascripts/resizable.js → public/vendor/resizable.js
View
File renamed without changes
4,410 public/vendor/s2.js
View
4,410 additions, 0 deletions not shown
0  public/javascripts/scrollbar.js → public/vendor/scrollbar.js
View
File renamed without changes
0  public/javascripts/selection.js → public/vendor/selection.js
View
File renamed without changes
0  public/javascripts/selectmultiple.js → public/vendor/selectmultiple.js
View
File renamed without changes
0  public/javascripts/slider.js → public/vendor/slider.js
View
File renamed without changes
0  public/javascripts/sound.js → public/vendor/sound.js
View
File renamed without changes
0  public/javascripts/swfobject.js → public/vendor/swfobject.js
View
File renamed without changes
0  public/javascripts/tabs.js → public/vendor/tabs.js
View
File renamed without changes
0  public/javascripts/textarea.js → public/vendor/textarea.js
View
File renamed without changes
0  public/javascripts/unittest.js → public/vendor/unittest.js
View
File renamed without changes
0  public/javascripts/web_socket.js → public/vendor/web_socket.js
View
File renamed without changes
0  public/javascripts/window.js → public/vendor/window.js
View
File renamed without changes
89 spec/sonia/config_spec.rb
View
@@ -0,0 +1,89 @@
+require 'spec_helper'
+
+require 'sonia/config'
+
+describe Sonia::Config do
+ describe "#new" do
+ let(:data) {{
+ :name => 'Sonia',
+ :nested => {
+ :one => 1,
+ :two => 2
+ }
+ }}
+
+ subject { Sonia::Config.new(data) }
+
+
+ its(:name) { should == 'Sonia' }
+ its(:nested) { should be_kind_of Sonia::Config }
+ it "has nested data" do
+ subject.nested.one.should == 1
+ subject.nested.two.should == 2
+ end
+ end
+
+ describe "#[]" do
+ let(:data) {{ :name => 'Sonia' }}
+ subject { Sonia::Config.new(data) }
+
+ it "returns same data" do
+ subject.name.should == 'Sonia'
+ subject[:name].should == 'Sonia'
+ subject["name"].should == 'Sonia'
+ end
+ end
+
+ describe "#[]=" do
+ let(:data) {{ :name => 'Sonia' }}
+ subject { Sonia::Config.new(data) }
+
+ it "allows updating data" do
+ subject.name.should == 'Sonia'
+
+ subject[:name] = "Piotr"
+ subject.name.should == 'Piotr'
+ subject[:name].should == 'Piotr'
+ subject["name"].should == 'Piotr'
+
+ subject["name"] = "John"
+ subject.name.should == 'John'
+ subject[:name].should == 'John'
+ subject["name"].should == 'John'
+ end
+ end
+
+ describe "#each" do
+ let(:data) {{ :name => 'Sonia', :age => 21 }}
+ subject { Sonia::Config.new(data) }
+
+ it "returns enumerator" do
+ subject.each.should be_kind_of(Enumerator)
+ end
+
+ it "allows to iterate over keys" do
+ hash = {}
+ subject.each do |k, v|
+ hash[k] = v
+ end
+
+ hash.keys.size.should == 2
+ hash.values.size.should == 2
+
+ hash.keys.should include(:name)
+ hash.keys.should include(:age)
+
+ hash.values.should include(21)
+ hash.values.should include('Sonia')
+ end
+ end
+
+ describe "#to_hash" do
+ let(:data) {{ "age" => 21 }}
+ subject { Sonia::Config.new(data) }
+
+ it "returns whole config data" do
+ subject.to_hash.should == { :age => 21 }
+ end
+ end
+end
7 spec/sonia_spec.rb
View
@@ -1,7 +0,0 @@
-require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
-
-describe "Sonia" do
- it "fails" do
- fail "hey buddy, you should probably rename this file and start specing for real"
- end
-end
1  spec/spec.opts
View
@@ -1 +1,2 @@
--color
+--format=nested
BIN  vendor/cache/gemcutter-0.5.0.gem
View
Binary file not shown
BIN  vendor/cache/git-1.2.5.gem
View
Binary file not shown
BIN  vendor/cache/jeweler-1.4.0.gem
View
Binary file not shown
BIN  vendor/cache/json_pure-1.4.3.gem
View
Binary file not shown
BIN  vendor/cache/rspec-1.3.0.gem
View
Binary file not shown
BIN  vendor/cache/rubyforge-2.0.4.gem
View
Binary file not shown
BIN  vendor/cache/yard-0.5.4.gem
View
Binary file not shown
1  views/index.haml
View
@@ -3,6 +3,7 @@
%head
%title Sonia - Awesome Office Dashboard
%meta(charset="utf-8")
+ %link(rel="icon" href="favicon.ico" type="image/x-icon")
%link(rel="apple-touch-icon" href="/images/sonia_apple_touch.png")
%body
%h1 project sonia
2  widgets/campfire/campfire.js
View
@@ -20,7 +20,7 @@ var Campfire = Class.create(Widget, {
this.container.insert(this.iconContainer);
this.container.insert(this.contentContainer);
- new Draggable(this.container, { scroll: window });
+ this.makeDraggable();
},
update: function() {
2  widgets/foursquare/foursquare.js
View
@@ -18,7 +18,7 @@ var Foursquare = Class.create(Widget, {
this.container.insert(this.buildWidgetIcon());
this.container.insert(this.checkinsContainer);
- new Draggable(this.container, { scroll: window });
+ this.makeDraggable();
},
update: function() {
this.checkinsContainer.childElements().invoke('remove');
2  widgets/github/github.js
View
@@ -17,7 +17,7 @@ var Github = Class.create(Widget, {
this.container.insert(this.iconContainer);
this.container.insert(this.contentContainer);
- new Draggable(this.container, { scroll: window });
+ this.makeDraggable();
},
update: function() {
2  widgets/icinga/icinga.js
View
@@ -20,7 +20,7 @@ var Icinga = Class.create(Widget, {
this.container.insert(this.iconContainer);
this.container.insert(this.contentContainer);
- new Draggable(this.container, { scroll: window });
+ this.makeDraggable();
},
update: function() {
2  widgets/rss/rss.js
View
@@ -17,7 +17,7 @@ var RSS = Class.create(Widget, {
this.container.insert(this.iconContainer);
this.container.insert(this.contentContainer);
- new Draggable(this.container, { scroll: window });
+ this.makeDraggable();
},
update: function() {
2  widgets/tfl/tfl.js
View
@@ -20,7 +20,7 @@ var Tfl = Class.create(Widget, {
this.container.insert(this.iconContainer);
this.container.insert(this.contentContainer);
- new Draggable(this.container, { scroll: window });
+ this.makeDraggable();
},
update: function() {
2  widgets/twitter/twitter.js
View
@@ -19,7 +19,7 @@ var Twitter = Class.create(Widget, {
this.container.insert(this.buildWidgetIcon());
this.container.insert(this.messagesContainer);
- new Draggable(this.container, { scroll: window });
+ this.makeDraggable();
},
update: function() {
2  widgets/twitter/twitter.rb
View
@@ -61,7 +61,7 @@ def handle_friends_response(http)
connect_to_stream
}
else
- log_unsuccessful_response_body(http1.response)
+ log_unsuccessful_response_body(http.response)
end
rescue => e
log_backtrace(e)
2  widgets/yahoo_weather/yahoo_weather.js
View
@@ -17,7 +17,7 @@ var YahooWeather = Class.create(Widget, {
this.container.insert(this.iconContainer);
this.container.insert(this.contentContainer);
- new Draggable(this.container, { scroll: window });
+ this.makeDraggable();
},
update: function() {
Please sign in to comment.
Something went wrong with that request. Please try again.