diff --git a/app/assets/javascripts/discourse/components/search.js b/app/assets/javascripts/discourse/components/search.js index ae7338771..a05a28e1a 100644 --- a/app/assets/javascripts/discourse/components/search.js +++ b/app/assets/javascripts/discourse/components/search.js @@ -12,13 +12,20 @@ Discourse.Search = { @method forTerm @param {String} term The term to search for - @param {String} typeFilter An optional filter to restrict the search by type + @param {Object} opts Options for searching + @param {String} opts.typeFilter Filter our results to one type only + @param {Ember.Object} opts.searchContext data to help searching within a context (say, a category or user) @return {Promise} a promise that resolves the search results **/ - forTerm: function(term, typeFilter) { - return Discourse.ajax('/search', { - data: { term: term, type_filter: typeFilter } - }); + forTerm: function(term, opts) { + if (!opts) opts = {}; + + // Only include the data we have + var data = { term: term } + if (opts.typeFilter) data.typeFilter = opts.typeFilter; + if (opts.searchContext) data.search_context = opts.searchContext; + + return Discourse.ajax('/search', { data: data }); } } diff --git a/app/assets/javascripts/discourse/controllers/composer_controller.js b/app/assets/javascripts/discourse/controllers/composer_controller.js index f209d5cc8..b0940bea2 100644 --- a/app/assets/javascripts/discourse/controllers/composer_controller.js +++ b/app/assets/javascripts/discourse/controllers/composer_controller.js @@ -27,6 +27,10 @@ Discourse.ComposerController = Discourse.Controller.extend({ if (c) return c.appendText(text); }, + categories: function() { + return Discourse.Category.list(); + }.property(), + save: function(force) { var composer, _this = this, @@ -35,6 +39,13 @@ Discourse.ComposerController = Discourse.Controller.extend({ buttons; composer = this.get('content'); + + if( composer.get('cantSubmitPost') ) { + this.set('view.showTitleTip', true); + this.set('view.showReplyTip', true); + return; + } + composer.set('disableDrafts', true); // for now handle a very narrow use case @@ -324,6 +335,8 @@ Discourse.ComposerController = Discourse.Controller.extend({ close: function() { this.set('content', null); this.set('view.content', null); + this.set('view.showTitleTip', false); + this.set('view.showReplyTip', false); }, closeIfCollapsed: function() { diff --git a/app/assets/javascripts/discourse/controllers/header_controller.js b/app/assets/javascripts/discourse/controllers/header_controller.js index 6d60c8437..57529bb47 100644 --- a/app/assets/javascripts/discourse/controllers/header_controller.js +++ b/app/assets/javascripts/discourse/controllers/header_controller.js @@ -14,7 +14,11 @@ Discourse.HeaderController = Discourse.Controller.extend({ var topic = this.get('topic'); if (topic) topic.toggleStar(); return false; - } + }, + + categories: function() { + return Discourse.Category.list(); + }.property() }); diff --git a/app/assets/javascripts/discourse/controllers/list_controller.js b/app/assets/javascripts/discourse/controllers/list_controller.js index 9c9bc4b42..c781917f0 100644 --- a/app/assets/javascripts/discourse/controllers/list_controller.js +++ b/app/assets/javascripts/discourse/controllers/list_controller.js @@ -8,21 +8,17 @@ **/ Discourse.ListController = Discourse.Controller.extend({ currentUserBinding: 'Discourse.currentUser', - categoriesBinding: 'Discourse.site.categories', categoryBinding: 'topicList.category', canCreateCategory: false, canCreateTopic: false, needs: ['composer', 'modal', 'listTopics'], availableNavItems: function() { - var hasCategories, loggedOn, summary; - summary = this.get('filterSummary'); - loggedOn = !!Discourse.get('currentUser'); - hasCategories = !!this.get('categories'); + var summary = this.get('filterSummary'); + var loggedOn = !!Discourse.get('currentUser'); return Discourse.SiteSettings.top_menu.split("|").map(function(i) { return Discourse.NavItem.fromText(i, { loggedOn: loggedOn, - hasCategories: hasCategories, countSummary: summary }); }).filter(function(i) { diff --git a/app/assets/javascripts/discourse/controllers/search_controller.js b/app/assets/javascripts/discourse/controllers/search_controller.js index f01cc4d68..c93fbc80a 100644 --- a/app/assets/javascripts/discourse/controllers/search_controller.js +++ b/app/assets/javascripts/discourse/controllers/search_controller.js @@ -25,7 +25,12 @@ Discourse.SearchController = Em.ArrayController.extend(Discourse.Presence, { var searchController = this; this.set('count', 0); - return Discourse.Search.forTerm(term, typeFilter).then(function(results) { + var searcher = Discourse.Search.forTerm(term, { + typeFilter: typeFilter, + searchContext: searchController.get('searchContext') + }); + + return searcher.then(function(results) { searchController.set('results', results); if (results) { searchController.set('noResults', results.length === 0); diff --git a/app/assets/javascripts/discourse/controllers/topic_controller.js b/app/assets/javascripts/discourse/controllers/topic_controller.js index 0f941d238..ead6a0b02 100644 --- a/app/assets/javascripts/discourse/controllers/topic_controller.js +++ b/app/assets/javascripts/discourse/controllers/topic_controller.js @@ -29,6 +29,9 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected return (this.get('selectedPostsCount') > 0); }.property('selectedPostsCount'), + categories: function() { + return Discourse.Category.list(); + }.property(), canSelectAll: Em.computed.not('allPostsSelected'), diff --git a/app/assets/javascripts/discourse/helpers/application_helpers.js b/app/assets/javascripts/discourse/helpers/application_helpers.js index 44d86537e..dd8caec7b 100644 --- a/app/assets/javascripts/discourse/helpers/application_helpers.js +++ b/app/assets/javascripts/discourse/helpers/application_helpers.js @@ -98,6 +98,21 @@ Ember.Handlebars.registerHelper('inputTip', function(options) { return Ember.Handlebars.helpers.view.call(this, Discourse.InputTipView, options); }); +/** + Inserts a Discourse.PopupInputTipView + + @method popupInputTip + @for Handlebars +**/ +Ember.Handlebars.registerHelper('popupInputTip', function(options) { + var hash = options.hash, + types = options.hashTypes; + + normalizeHash(hash, types); + + return Ember.Handlebars.helpers.view.call(this, Discourse.PopupInputTipView, options); +}); + /** Produces a bound link to a category diff --git a/app/assets/javascripts/discourse/models/category.js b/app/assets/javascripts/discourse/models/category.js index 96a995c5d..46bc8af49 100644 --- a/app/assets/javascripts/discourse/models/category.js +++ b/app/assets/javascripts/discourse/models/category.js @@ -20,6 +20,10 @@ Discourse.Category = Discourse.Model.extend({ this.set("groups", Em.A(this.groups)); }, + searchContext: function() { + return ({ type: 'category', id: this.get('id') }); + }.property('id'), + url: function() { return Discourse.getURL("/category/") + (this.get('slug')); }.property('name'), diff --git a/app/assets/javascripts/discourse/models/composer.js b/app/assets/javascripts/discourse/models/composer.js index c4a287379..68ceff6f6 100644 --- a/app/assets/javascripts/discourse/models/composer.js +++ b/app/assets/javascripts/discourse/models/composer.js @@ -276,7 +276,9 @@ Discourse.Composer = Discourse.Model.extend({ }, save: function(opts) { - return this.get('editingPost') ? this.editPost(opts) : this.createPost(opts); + if( !this.get('cantSubmitPost') ) { + return this.get('editingPost') ? this.editPost(opts) : this.createPost(opts); + } }, // When you edit a post diff --git a/app/assets/javascripts/discourse/models/nav_item.js b/app/assets/javascripts/discourse/models/nav_item.js index 0e256d665..7d268d634 100644 --- a/app/assets/javascripts/discourse/models/nav_item.js +++ b/app/assets/javascripts/discourse/models/nav_item.js @@ -34,7 +34,7 @@ Discourse.NavItem.reopenClass({ testName = name.split("/")[0]; if (!opts.loggedOn && !validAnon.contains(testName)) return null; - if (!opts.hasCategories && testName === "categories") return null; + if (!Discourse.Category.list() && testName === "categories") return null; if (!validNavNames.contains(testName)) return null; opts = { diff --git a/app/assets/javascripts/discourse/models/post.js b/app/assets/javascripts/discourse/models/post.js index fcd225162..c86171a2c 100644 --- a/app/assets/javascripts/discourse/models/post.js +++ b/app/assets/javascripts/discourse/models/post.js @@ -128,7 +128,7 @@ Discourse.Post = Discourse.Model.extend({ return _this.get("actionByName." + (item.get('name_key')) + ".can_act"); }); return flags; - }.property('Discourse.site.flagTypes', 'actions_summary.@each.can_act'), + }.property('actions_summary.@each.can_act'), actionsHistory: function() { if (!this.present('actions_summary')) return null; @@ -220,7 +220,7 @@ Discourse.Post = Discourse.Model.extend({ obj.actions_summary.each(function(a) { var actionSummary; a.post = post; - a.actionType = Discourse.get("site").postActionTypeById(a.id); + a.actionType = Discourse.Site.instance().postActionTypeById(a.id); actionSummary = Discourse.ActionSummary.create(a); post.get('actions_summary').pushObject(actionSummary); lookup.set(a.actionType.get('name_key'), actionSummary); @@ -278,10 +278,9 @@ Discourse.Post.reopenClass({ if (result.actions_summary) { lookup = Em.Object.create(); result.actions_summary = result.actions_summary.map(function(a) { - var actionSummary; a.post = result; - a.actionType = Discourse.get("site").postActionTypeById(a.id); - actionSummary = Discourse.ActionSummary.create(a); + a.actionType = Discourse.Site.instance().postActionTypeById(a.id); + var actionSummary = Discourse.ActionSummary.create(a); lookup.set(a.actionType.get('name_key'), actionSummary); return actionSummary; }); @@ -290,8 +289,7 @@ Discourse.Post.reopenClass({ }, create: function(obj, topic) { - var result; - result = this._super(obj); + var result = this._super(obj); this.createActionSummary(result); if (obj.reply_to_user) { result.set('reply_to_user', Discourse.User.create(obj.reply_to_user)); diff --git a/app/assets/javascripts/discourse/models/topic.js b/app/assets/javascripts/discourse/models/topic.js index d7e1a2696..b6df4e317 100644 --- a/app/assets/javascripts/discourse/models/topic.js +++ b/app/assets/javascripts/discourse/models/topic.js @@ -7,17 +7,16 @@ @module Discourse **/ Discourse.Topic = Discourse.Model.extend({ - categoriesBinding: 'Discourse.site.categories', - fewParticipants: (function() { + fewParticipants: function() { if (!this.present('participants')) return null; return this.get('participants').slice(0, 3); - }).property('participants'), + }.property('participants'), - canConvertToRegular: (function() { + canConvertToRegular: function() { var a = this.get('archetype'); return a !== 'regular' && a !== 'private_message'; - }).property('archetype'), + }.property('archetype'), convertArchetype: function(archetype) { var a = this.get('archetype'); @@ -30,11 +29,13 @@ Discourse.Topic = Discourse.Model.extend({ } }, + searchContext: function() { + return ({ type: 'topic', id: this.get('id') }); + }.property('id'), + category: function() { - if (this.get('categories')) { - return this.get('categories').findProperty('name', this.get('categoryName')); - } - }.property('categoryName', 'categories'), + return Discourse.Category.list().findProperty('name', this.get('categoryName')); + }.property('categoryName'), shareUrl: function(){ var user = Discourse.get('currentUser'); @@ -220,6 +221,7 @@ Discourse.Topic = Discourse.Model.extend({ // If loading the topic succeeded... var afterTopicLoaded = function(result) { + var closestPostNumber, lastPost, postDiff; // Update the slug if different @@ -246,6 +248,7 @@ Discourse.Topic = Discourse.Model.extend({ if (result.suggested_topics) { topic.set('suggested_topics', Em.A()); } + topic.mergeAttributes(result, { suggested_topics: Discourse.Topic }); topic.set('posts', Em.A()); if (opts.trackVisit && result.draft && result.draft.length > 0) { @@ -261,17 +264,18 @@ Discourse.Topic = Discourse.Model.extend({ // Okay this is weird, but let's store the length of the next post when there lastPost = null; result.posts.each(function(p) { - var post; p.scrollToAfterInsert = opts.nearPost; - post = Discourse.Post.create(p); + var post = Discourse.Post.create(p); post.set('topic', topic); topic.get('posts').pushObject(post); lastPost = post; }); + topic.set('loaded', true); } var errorLoadingTopic = function(result) { + topic.set('errorLoading', true); // If the result was 404 the post is not found diff --git a/app/assets/javascripts/discourse/models/user.js b/app/assets/javascripts/discourse/models/user.js index 080bb6c63..fa1f462f8 100644 --- a/app/assets/javascripts/discourse/models/user.js +++ b/app/assets/javascripts/discourse/models/user.js @@ -28,6 +28,10 @@ Discourse.User = Discourse.Model.extend({ return Discourse.Utilities.avatarUrl(this.get('username'), 'small', this.get('avatar_template')); }).property('username'), + searchContext: function() { + return ({ type: 'user', id: this.get('username_lower') }); + }.property('username_lower'), + /** This user's website. diff --git a/app/assets/javascripts/discourse/routes/application_route.js b/app/assets/javascripts/discourse/routes/application_route.js index 19c986af4..1b067d203 100644 --- a/app/assets/javascripts/discourse/routes/application_route.js +++ b/app/assets/javascripts/discourse/routes/application_route.js @@ -8,8 +8,7 @@ **/ Discourse.ApplicationRoute = Discourse.Route.extend({ setupController: function(controller) { - Discourse.set('site', Discourse.Site.instance()); - + //Discourse.set('site', Discourse.Site.instance()); var currentUser = PreloadStore.get('currentUser'); if (currentUser) { Discourse.set('currentUser', Discourse.User.create(currentUser)); diff --git a/app/assets/javascripts/discourse/routes/list_category_route.js b/app/assets/javascripts/discourse/routes/list_category_route.js index 7ac953083..a3fc1f599 100644 --- a/app/assets/javascripts/discourse/routes/list_category_route.js +++ b/app/assets/javascripts/discourse/routes/list_category_route.js @@ -47,7 +47,7 @@ Discourse.ListCategoryRoute = Discourse.FilteredListRoute.extend({ this._super(); // Add a search context - this.controllerFor('search').set('searchContext', this.modelFor('listCategory')); + this.controllerFor('search').set('searchContext', this.modelFor('listCategory').get('searchContext')); }, deactivate: function() { diff --git a/app/assets/javascripts/discourse/routes/topic_route.js b/app/assets/javascripts/discourse/routes/topic_route.js index 65a3b2eaf..34eb93415 100644 --- a/app/assets/javascripts/discourse/routes/topic_route.js +++ b/app/assets/javascripts/discourse/routes/topic_route.js @@ -25,7 +25,7 @@ Discourse.TopicRoute = Discourse.Route.extend({ Discourse.set('transient.lastTopicIdViewed', parseInt(topic.get('id'), 10)); // Set the search context - this.controllerFor('search').set('searchContext', topic); + this.controllerFor('search').set('searchContext', topic.get('searchContext')); }, deactivate: function() { diff --git a/app/assets/javascripts/discourse/routes/user_route.js b/app/assets/javascripts/discourse/routes/user_route.js index 8cb799187..d033f2654 100644 --- a/app/assets/javascripts/discourse/routes/user_route.js +++ b/app/assets/javascripts/discourse/routes/user_route.js @@ -28,7 +28,7 @@ Discourse.UserRoute = Discourse.Route.extend({ }); // Add a search context - this.controllerFor('search').set('searchContext', user); + this.controllerFor('search').set('searchContext', user.get('searchContext')); }, deactivate: function() { diff --git a/app/assets/javascripts/discourse/templates/composer.js.handlebars b/app/assets/javascripts/discourse/templates/composer.js.handlebars index 800fcf194..aab1e64fe 100644 --- a/app/assets/javascripts/discourse/templates/composer.js.handlebars +++ b/app/assets/javascripts/discourse/templates/composer.js.handlebars @@ -32,9 +32,14 @@ {{#if content.creatingPrivateMessage}} {{view Discourse.UserSelector topicIdBinding="controller.controllers.topic.content.id" excludeCurrentUser="true" id="private-message-users" class="span8" placeholderKey="composer.users_placeholder" tabindex="1" usernamesBinding="content.targetUsernames"}} {{/if}} - {{textField value=content.title tabindex="2" id="reply-title" maxlength="255" class="span8" placeholderKey="composer.title_placeholder"}} + +