diff --git a/config/assets.yml b/config/assets.yml index 3f6252a96..7c3a66341 100644 --- a/config/assets.yml +++ b/config/assets.yml @@ -35,6 +35,7 @@ javascripts: - public/javascripts/view.js - public/javascripts/stream.js - public/javascripts/content-updater.js + - public/javascripts/aspects-dropdown.js - public/javascripts/contact-edit.js - public/javascripts/contact-list.js - public/javascripts/aspect-sorting.js diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml index c24758636..f352f3371 100644 --- a/config/locales/javascript/javascript.en.yml +++ b/config/locales/javascript/javascript.en.yml @@ -67,6 +67,4 @@ en: photo_uploader: looking_good: "OMG, you look awesome!" tags: - wasnt_that_interesting: "OK, I suppose #{{tagName}} wasn't all that interesting..." - inviter: - sending: "sending, please wait..." \ No newline at end of file + wasnt_that_interesting: "OK, I suppose #{{tagName}} wasn't all that interesting..." diff --git a/public/javascripts/aspects-dropdown.js b/public/javascripts/aspects-dropdown.js index e69de29bb..61f035d17 100644 --- a/public/javascripts/aspects-dropdown.js +++ b/public/javascripts/aspects-dropdown.js @@ -0,0 +1,61 @@ +// Copyright (c) 2010-2011, Diaspora Inc. This file is +// licensed under the Affero General Public License version 3 or later. See +// the COPYRIGHT file. + +var AspectsDropdown = { + updateNumber: function(dropdown, personId, number, inAspectClass){ + var button = dropdown.parents(".dropdown").children('.button.toggle'), + selectedAspects = dropdown.children(".selected").length, + allAspects = dropdown.children().length, + replacement; + + if (number == 0) { + button.removeClass(inAspectClass); + if( dropdown.closest('#publisher').length ) { + replacement = Diaspora.I18n.t("aspect_dropdown.select_aspects"); + } else { + replacement = Diaspora.I18n.t("aspect_dropdown.add_to_aspect"); + /* flash message prompt */ + var message = Diaspora.I18n.t("aspect_dropdown.stopped_sharing_with", {name: dropdown.data('person-short-name')}); + Diaspora.page.flashMessages.render({success: true, notice: message}); + } + }else if (selectedAspects == allAspects) { + replacement = Diaspora.I18n.t('aspect_dropdown.all_aspects'); + }else if (number == 1) { + button.addClass(inAspectClass); + replacement = dropdown.find(".selected").first().text(); + /* flash message prompt */ + if( dropdown.closest('#publisher').length == 0 ) { + var message = Diaspora.I18n.t("aspect_dropdown.started_sharing_with", {name: dropdown.data('person-short-name')}); + Diaspora.page.flashMessages.render({success: true, notice: message}); + } + }else { + replacement = Diaspora.I18n.t('aspect_dropdown.toggle', { count: number.toString()}) + } + + button.text(replacement + ' ▼'); + }, + + toggleCheckbox: function(check) { + if(!check.hasClass('radio')){ + var selectedAspects = check.closest(".dropdown").find("li.radio"); + AspectsDropdown.uncheckGroup(selectedAspects); + } + + check.toggleClass('selected'); + }, + + toggleRadio: function(check) { + var selectedAspects = check.closest(".dropdown").find("li"); + + AspectsDropdown.uncheckGroup(selectedAspects); + AspectsDropdown.toggleCheckbox(check); + }, + + uncheckGroup: function(elements){ + $.each(elements, function(index, value) { + $(value).removeClass('selected'); + }); + } +}; + diff --git a/public/javascripts/contact-edit.js b/public/javascripts/contact-edit.js new file mode 100644 index 000000000..4e55200df --- /dev/null +++ b/public/javascripts/contact-edit.js @@ -0,0 +1,89 @@ +// Copyright (c) 2010-2011, Diaspora Inc. This file is +// licensed under the Affero General Public License version 3 or later. See +// the COPYRIGHT file. + +var ContactEdit = { + init: function(){ + $.extend(ContactEdit, AspectsDropdown); + $('.dropdown.aspect_membership .dropdown_list > li, .dropdown.inviter .dropdown_list > li').live('click', function(evt){ + + ContactEdit.processClick($(this), evt); + }); + }, + + updateNumber: function(dropdown, personId, number){ + var button = dropdown.parents(".dropdown").children('.button.toggle'), + replacement; + + if (number == 0) { + button.removeClass("in_aspects"); + replacement = Diaspora.I18n.t("aspect_dropdown.toggle.zero"); + }else if (number == 1) { + button.addClass("in_aspects"); + replacement = dropdown.find(".selected").first().text(); + }else if (number < 3) { + replacement = Diaspora.I18n.t('aspect_dropdown.toggle.few', { count: number.toString()}) + }else if (number > 3) { + replacement = Diaspora.I18n.t('aspect_dropdown.toggle.many', { count: number.toString()}) + }else { + //the above one are a tautology, but I want to have them here once for once we figure out a neat way i18n them + replacement = Diaspora.I18n.t('aspect_dropdown.toggle.other', { count: number.toString()}) + ContactEdit.toggleAspectMembership(li, evt); + } + }, + + inviteFriend: function(li, evt) { + $.post('/services/inviter/facebook.json', { + "aspect_id" : li.data("aspect_id"), + "uid" : li.parent().data("service_uid") + }, function(data){ + ContactEdit.processSuccess(li, evt, data); + }); + }, + + processSuccess: function(element, evt, data) { + element.removeClass('loading') + if (data.url != undefined) { + window.location = data.url; + } else { + element.toggleClass("selected"); + Diaspora.widgets.flashes.render({'success':true, 'notice':data.message}); + } + }, + + processClick: function(li, evt){ + var dropdown = li.closest('.dropdown'); + li.addClass('loading'); + if (dropdown.hasClass('inviter')) { + ContactEdit.inviteFriend(li, evt); + dropdown.html('sending, please wait...'); + } + else { + ContactEdit.toggleAspectMembership(li, evt); + } + }, + + toggleAspectMembership: function(li, evt) { + var button = li.find('.button'); + if(button.hasClass('disabled') || li.hasClass('newItem')){ return; } + + var selected = li.hasClass("selected"), + routedId = selected ? "/42" : ""; + + $.post("/aspect_memberships" + routedId + ".json", { + "aspect_id": li.data("aspect_id"), + "person_id": li.parent().data("person_id"), + "_method": (selected) ? "DELETE" : "POST" + }, function(aspectMembership) { + li.removeClass("loading"); + ContactEdit.toggleCheckbox(li); + ContactEdit.updateNumber(li.closest(".dropdown_list"), li.parent().data("person_id"), aspectMembership.aspect_ids.length, 'in_aspects'); + + Diaspora.page.publish("aspectDropdown/updated", [li.parent().data("person_id"), li.parents(".dropdown").parent(".right").html()]); + }); + } +}; + +$(document).ready(function(){ + ContactEdit.init(); +}); diff --git a/public/javascripts/pages/contacts-index.js b/public/javascripts/pages/contacts-index.js index 35a60cf32..e036172a3 100644 --- a/public/javascripts/pages/contacts-index.js +++ b/public/javascripts/pages/contacts-index.js @@ -4,10 +4,6 @@ Diaspora.Pages.ContactsIndex = function() { this.subscribe("page/ready", function(evt, document) { self.infiniteScroll = self.instantiate("InfiniteScroll"); - $(".aspect_membership.dropdown").each(function() { - self.instantiate("AspectsDropdown", $(this)); - }); - $('.conversation_button').twipsy({position: 'below'}); }); }; diff --git a/public/javascripts/pages/people-show.js b/public/javascripts/pages/people-show.js index b05521207..84c0173b8 100644 --- a/public/javascripts/pages/people-show.js +++ b/public/javascripts/pages/people-show.js @@ -2,7 +2,6 @@ Diaspora.Pages.PeopleShow = function() { var self = this; this.subscribe("page/ready", function(evt, document) { - self.aspectsDropdown = self.instantiate("AspectsDropdown", document.find(".aspect_membership.dropdown")); self.stream = self.instantiate("Stream", document.find("#main_stream")); self.infiniteScroll = self.instantiate("InfiniteScroll"); }); diff --git a/public/javascripts/publisher.js b/public/javascripts/publisher.js index 9278337c3..abad86f9a 100644 --- a/public/javascripts/publisher.js +++ b/public/javascripts/publisher.js @@ -379,12 +379,21 @@ var Publisher = { }, bindAspectToggles: function() { - Publisher.aspectsDropdown = Diaspora.BaseWidget.instantiate("AspectsDropdown", $("#publisher .dropdown")); - Publisher.aspectsDropdown.aspectSelectors.click(function() { - Publisher.toggleAspectIds($(this)); + $('#publisher .dropdown .dropdown_list li').bind("click", function(evt){ + var li = $(this), + button = li.parent('.dropdown').find('.button'); + + if(li.hasClass('radio')){ + AspectsDropdown.toggleRadio(li); + } else { + AspectsDropdown.toggleCheckbox(li); + } + + AspectsDropdown.updateNumber(li.closest(".dropdown_list"), null, li.parent().find('li.selected').length, ''); + + Publisher.toggleAspectIds(li); }); }, - beforeSubmit: function(){ if($("#publisher .content_creation form #aspect_ids_").length == 0){ alert(Diaspora.I18n.t('publisher.at_least_one_aspect')); diff --git a/public/javascripts/widgets/aspects-dropdown.js b/public/javascripts/widgets/aspects-dropdown.js deleted file mode 100644 index 2c9d776e2..000000000 --- a/public/javascripts/widgets/aspects-dropdown.js +++ /dev/null @@ -1,133 +0,0 @@ -/* Copyright (c) 2010-2011, Diaspora Inc. This file is - * licensed under the Affero General Public License version 3 or later. See - * the COPYRIGHT file. - */ - -(function() { - var AspectsDropdown = function() { - var self = this; - - this.subscribe("widget/ready", function(evt, dropdown) { - $.extend(self, { - aspectSelectors: dropdown.find("li.aspect_selector"), - radioSelectors: dropdown.find("li.radio"), - dropdown: dropdown, - dropdownButton: dropdown.children(".button.toggle"), - dropdownList: dropdown.find("ul.dropdown_list"), - inviterDropdown: dropdown.hasClass("inviter"), - publisherDropdown: !!dropdown.closest("#publisher").length - }); - - self.personId = self.dropdownList.data("person_id"); - - self.aspectSelectors.click(self.aspectClicked); - self.radioSelectors.click(self.radioClicked); - }); - - this.aspectClicked = function(evt) { - var aspectListItem = $(this); - if (self.inviterDropdown) { - self.inviteFriend(aspectListItem); - } - else if(self.publisherDropdown) { - self.toggleAspectSelection(aspectListItem); - } - else { - self.toggleAspectMembership(aspectListItem); - } - }; - - this.radioClicked = function() { - self.aspectSelectors - .add(self.radioSelectors) - .not(this) - .removeClass("selected"); - - $(this).toggleClass("selected") - }; - - this.toggleAspectSelection = function(aspect) { - self.radioSelectors.removeClass("selected"); - - aspect.toggleClass("selected"); - }; - - this.inviteFriend = function(aspectListItem) { - self.dropdown.html(Diaspora.I18n.t("inviter.sending")); - $.post('/services/inviter/facebook.json', { - "aspect_id" : aspectListItem.data("aspect_id"), - "uid" : self.dropdownList.data("service_uid") - }, function(data) { - aspectListItem.removeClass("loading"); - if (typeof data.url !== "undefined") { - window.location = data.url; - } else { - aspectListItem.toggleClass("selected"); - - Diaspora.page.flashMessages.render({ - success: true, - notice: data.message - }); - } - }); - }; - - this.toggleAspectMembership = function(aspectListItem) { - var aspectId = aspectListItem.data("aspect_id"), - button = aspectListItem.find(".button"); - - if(button.hasClass("disabled") || aspectListItem.hasClass("newItem")) { return; } - - var selected = aspectListItem.hasClass("selected"), - routedId = selected ? "/42" : ""; - - aspectListItem.addClass("loading"); - - $.post("/aspect_memberships" + routedId + ".json", { - "aspect_id": aspectId, - "person_id": self.personId, - "_method": (selected) ? "DELETE" : "POST" - }, function() { - aspectListItem.removeClass("loading") - .toggleClass("selected"); - - self.updateDropdownText(); - - self.globalPublish("aspectDropdown/updated", [self.personId, self.dropdown.parent().html()]); - }); - }; - - this.updateDropdownText = function() { - var selectedAspects = self.dropdownList.children(".selected").length, - allAspects = self.dropdownList.children().length, - replacement; - - if (selectedAspects == 0) { - self.dropdownButton.removeClass("in_aspects"); - - if(self.dropdown.closest("#publisher").length) { - replacement = Diaspora.I18n.t("aspect_dropdown.select_aspects"); - } else { - replacement = Diaspora.I18n.t("aspect_dropdown.add_to_aspect"); - } - } - else if (selectedAspects === allAspects) { - replacement = Diaspora.I18n.t("aspect_dropdown.all_aspects"); - } - else if (selectedAspects === 1) { - self.dropdownButton.addClass("in_aspects"); - - replacement = self.dropdown.find(".selected:first").text(); - } - else if (selectedAspects > 1) { - replacement = Diaspora.I18n.t("aspect_dropdown.toggle", { - count: selectedAspects - }); - } - - self.dropdownButton.text(replacement + " ▼"); - } - }; - - Diaspora.Widgets.AspectsDropdown = AspectsDropdown; -})(); \ No newline at end of file diff --git a/public/javascripts/widgets/hovercard.js b/public/javascripts/widgets/hovercard.js index c8ad0e4fd..028fea325 100644 --- a/public/javascripts/widgets/hovercard.js +++ b/public/javascripts/widgets/hovercard.js @@ -24,7 +24,7 @@ $(document.body).delegate("a.hovercardable:not(.self)", "hover", self.handleHoverEvent); self.hoverCard.tip.hover(self.hoverCardHover, self.clearTimeout); - self.globalSubscribe("aspectDropdown/updated", function(evt, personId, dropdownHtml) { + self.subscribe("aspectDropdown/updated aspectDropdown/blurred", function(evt, personId, dropdownHtml) { self.dropdownCache.cache["/people/" + personId + "/aspect_membership_button"] = $(dropdownHtml).removeClass("active").get(0).outerHTML; }); }); @@ -79,7 +79,6 @@ self.dropdownCache.get(self.target.attr("data-hovercard") + "/aspect_membership_button", function(dropdown) { self.hoverCard.dropdownContainer.html(dropdown); - self.hoverCard.dropdownWidget = self.instantiate("AspectsDropdown", self.hoverCard.dropdownContainer.children()); self.hoverCard.tip.fadeIn(140); }); }; diff --git a/spec/javascripts/helpers/SpecHelper.js b/spec/javascripts/helpers/SpecHelper.js index b858686ec..ccb456878 100644 --- a/spec/javascripts/helpers/SpecHelper.js +++ b/spec/javascripts/helpers/SpecHelper.js @@ -22,6 +22,12 @@ beforeEach(function() { self.directionDetector = self.instantiate("DirectionDetector"); }); }; + + var Page = Diaspora.Pages["TestPage"]; + $.extend(Page.prototype, Diaspora.EventBroker.extend(Diaspora.BaseWidget)); + + Diaspora.page = new Page(); + Diaspora.page.publish("page/ready", [$(document.body)]) }); afterEach(function() { diff --git a/spec/javascripts/widgets/aspects-dropdown-spec.js b/spec/javascripts/widgets/aspects-dropdown-spec.js deleted file mode 100644 index cceab3a18..000000000 --- a/spec/javascripts/widgets/aspects-dropdown-spec.js +++ /dev/null @@ -1,116 +0,0 @@ -describe("Diaspora.Widgets.AspectsDropdown", function() { - var aspectsDropdownWidget, - aspectsDropdown; - - describe("when the dropdown is a publisher dropdown", function() { - beforeEach(function() { - spec.loadFixture("aspects_index"); - - Diaspora.Page = "TestPage"; - Diaspora.instantiatePage(); - - aspectsDropdown = $("#publisher .dropdown"); - aspectsDropdownWidget = Diaspora.BaseWidget.instantiate("AspectsDropdown", aspectsDropdown); - }); - - describe("clicking a radio button", function() { - describe("integration", function() { - it("calls AspectsDropdown#radioClicked", function() { - aspectsDropdownWidget = new Diaspora.Widgets.AspectsDropdown(); - - spyOn(aspectsDropdownWidget, "radioClicked"); - - aspectsDropdownWidget.publish("widget/ready", [aspectsDropdown]); - - aspectsDropdownWidget.radioSelectors.first().click(); - - expect(aspectsDropdownWidget.radioClicked).toHaveBeenCalled(); - }) - }); - - it("clears the selected aspects", function() { - var aspectSelectors = aspectsDropdown.find(".aspect_selector").click(); - - expect(aspectsDropdown).toContain("li.aspect_selector.selected"); - - aspectsDropdown.find(".radio:first").click(); - - expect(aspectsDropdown).not.toContain("li.aspect_selector.selected"); - }); - - it("clears selected radio buttons", function() { - aspectsDropdown.find(".selected").removeClass("selected"); - - var firstRadioSelector = aspectsDropdown.find(".radio:first"), - lastRadioSelector = aspectsDropdown.find(".radio:last"); - - expect(firstRadioSelector).not.toHaveClass("selected"); - expect(lastRadioSelector).not.toHaveClass("selected"); - - firstRadioSelector.click(); - - expect(firstRadioSelector).toHaveClass("selected"); - - lastRadioSelector.click(); - - expect(firstRadioSelector).not.toHaveClass("selected"); - expect(lastRadioSelector).toHaveClass("selected"); - }); - - it("toggles the radio selector", function() { - var radioSelector = aspectsDropdown.find(".radio:first"); - - expect(radioSelector).not.toHaveClass("selected"); - - radioSelector.click(); - - expect(radioSelector).toHaveClass("selected"); - - radioSelector.click(); - - expect(radioSelector).not.toHaveClass("selected"); - }); - }); - - describe("clicking an aspect", function() { - describe("integration", function() { - it("calls through to AspectsDropdown#toggleAspectSelection", function() { - aspectsDropdownWidget = new Diaspora.Widgets.AspectsDropdown(); - - spyOn(aspectsDropdownWidget, "toggleAspectSelection"); - - aspectsDropdownWidget.publish("widget/ready", [aspectsDropdown]); - - aspectsDropdownWidget.aspectSelectors.first().click(); - - expect(aspectsDropdownWidget.toggleAspectSelection).toHaveBeenCalled(); - }); - }); - - it("deselects the radio buttons", function() { - var aspectSelector = aspectsDropdownWidget.aspectSelectors.first(), - radioSelector = aspectsDropdown.find(".radio:last"); - - expect(radioSelector).toHaveClass("selected"); - - aspectSelector.click(); - - expect(radioSelector).not.toHaveClass("selected"); - }); - - it("toggles the aspect selector", function() { - var aspectSelector = aspectsDropdownWidget.aspectSelectors.first(); - - expect(aspectSelector).not.toHaveClass("selected"); - - aspectSelector.click(); - - expect(aspectSelector).toHaveClass("selected"); - - aspectSelector.click(); - - expect(aspectSelector).not.toHaveClass("selected"); - }); - }); - }); -}); \ No newline at end of file