diff --git a/.eslintignore b/.eslintignore index 1ecda00738..528b8358a1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -7,6 +7,7 @@ app/assets/javascripts/vendor.js app/assets/javascripts/locales/i18n.js app/assets/javascripts/defer/html-sanitizer-bundle.js app/assets/javascripts/discourse/lib/Markdown.Editor.js +app/assets/javascripts/ember-addons jsapp/lib/Markdown.Editor.js lib/javascripts/locale/ lib/javascripts/messageformat.js diff --git a/.eslintrc b/.eslintrc index 149d842488..d2a13ae262 100644 --- a/.eslintrc +++ b/.eslintrc @@ -90,10 +90,7 @@ "no-undef": 2, "no-unused-vars": 2, "no-with": 2, - "semi": [ - 0, - "never" - ], + "semi": 2, "strict": 0, "valid-typeof": 2, "wrap-iife": [ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f00d5d078e..98aa05e4ac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,129 +1,27 @@ # Contributing to Discourse -## Before You Start +## Important note for Developers -Anyone wishing to contribute to the **[Discourse/Discourse](https://github.com/discourse/discourse)** project **MUST read & sign the [Electronic Discourse Forums Contribution License Agreement](http://www.discourse.org/cla)**. The Discourse team is legally prevented from accepting any pull requests from users who have not signed the CLA first. +Anyone wishing to contribute to the [github.com/discourse/discourse](https://github.com/discourse/discourse) project **must read & sign our [Contributor License Agreement](http://www.discourse.org/cla)**. The Discourse team is legally prevented from accepting any pull requests from users who have not signed the CLA first. -## Reporting Bugs +For more information on -1. Always update to the most recent master release; the bug may already be resolved. +- how to set up your development environment +- first-time project suggestions +- code conventions +- step-by-step guide for GitHub commits -2. Search for similar issues on the [Discourse meta forum][m]; it may already be an identified problem. +**please read our [Discourse Development Contribution Guidelines](https://meta.discourse.org/t/discourse-development-contribution-guidelines/3823)** -3. Make sure you can reproduce your problem on our sandbox at [try.discourse.org](http://try.discourse.org) +## Everything Else -4. If this is a bug or problem that **requires any kind of extended discussion -- open [a topic on meta][m] about it**. +There are many other ways to contribute to Discourse besides code. We've outlined the most common ones below. -5. If possible, submit a Pull Request with a failing test. If you'd rather take matters into your own hands, fix the bug yourself (jump down to the "Contributing (Step-by-step)" section). +- [Reporting Bugs](https://meta.discourse.org/t/how-to-make-bug-reports-for-discourse/33070) +- [Requesting Features](https://meta.discourse.org/t/how-to-request-new-features-for-discourse/32986) +- [Translation](https://meta.discourse.org/t/contribute-a-translation-to-discourse/14882) +- Documentation (TBA) -6. When the bug is fixed, we will do our best to update the Discourse topic. +For anything else, just start a new topic on [Meta](https://meta.discourse.org/) and let us know what you're interested in working on. -## Requesting New Features - -1. Do not submit a feature request on GitHub; all feature requests on GitHub will be closed. Instead, visit the **[Discourse meta forum, features category](http://meta.discourse.org/category/feature)**, and search this list for similar feature requests. It's possible somebody has already asked for this feature or provided a pull request that we're still discussing. - -2. Provide a clear and detailed explanation of the feature you want and why it's important to add. The feature must apply to a wide array of users of Discourse; for smaller, more targeted "one-off" features, you might consider writing a plugin for Discourse. You may also want to provide us with some advance documentation on the feature, which will help the community to better understand where it will fit. - -3. If you're a Rock Star programmer, build the feature yourself (refer to the "Contributing (Step-by-step)" section below). - -## Contributing (Step-by-step) - -1. Clone the Repo: - - git clone git://github.com/discourse/discourse.git - -2. Create a new Branch: - - cd discourse - git checkout -b new_discourse_branch - - > Please keep your code clean: one feature or bug-fix per branch. If you find another bug, you want to fix while being in a new branch, please fix it in a separated branch instead. - -3. Code - * Adhere to common conventions you see in the existing code - * Include tests, and ensure they pass - * Search to see if your new functionality has been discussed on [the Discourse meta forum](http://meta.discourse.org), and include updates as appropriate - -4. Follow the Coding Conventions - * two spaces, no tabs - * no trailing whitespaces, blank lines should have no spaces - * use spaces around operators, after commas, colons, semicolons, around `{` and before `}` - * no space after `(`, `[` or before `]`, `)` - * use Ruby 1.9 hash syntax: prefer `{ a: 1 }` over `{ :a => 1 }` - * prefer `class << self; def method; end` over `def self.method` for class methods - * prefer `{ ... }` over `do ... end` for single-line blocks, avoid using `{ ... }` for multi-line blocks - * avoid `return` when not required - - > However, please note that **pull requests consisting entirely of style changes are not welcome on this project**. Style changes in the context of pull requests that also refactor code, fix bugs, improve functionality *are* welcome. - -5. Commit - - For every commit please write a short (max 72 characters) summary in the first line followed with a blank line and then more detailed descriptions of the change. Use markdown syntax for simple styling. - - **NEVER leave the commit message blank!** Provide a detailed, clear, and complete description of your commit! - - -6. Update your branch - - ``` - git fetch origin - git rebase origin/master - ``` - -7. Fork - - ``` - git remote add mine git@github.com:/discourse.git - ``` - -8. Push to your remote - - ``` - git push mine new_discourse_branch - ``` - -9. Issue a Pull Request - - Before submitting a pull-request, clean up the history, go over your commits and squash together minor changes and fixes into the corresponding commits. You can squash commits with the interactive rebase command: - - ``` - git fetch origin - git checkout new_discourse_branch - git rebase origin/master - git rebase -i - - < the editor opens and allows you to change the commit history > - < follow the instructions on the bottom of the editor > - - git push -f mine new_discourse_branch - ``` - - - In order to make a pull request, - * Navigate to the Discourse repository you just pushed to (e.g. https://github.com/your-user-name/discourse) - * Click "Pull Request". - * Write your branch name in the branch field (this is filled with "master" by default) - * Click "Update Commit Range". - * Ensure the changesets you introduced are included in the "Commits" tab. - * Ensure that the "Files Changed" incorporate all of your changes. - * Fill in some details about your potential patch including a meaningful title. - * Click "Send pull request". - - Thanks for that -- we'll get to your pull request ASAP, we love pull requests! - -10. Responding to Feedback - - The Discourse team may recommend adjustments to your code. Part of interacting with a healthy open-source community requires you to be open to learning new techniques and strategies; *don't get discouraged!* Remember: if the Discourse team suggest changes to your code, **they care enough about your work that they want to include it**, and hope that you can assist by implementing those revisions on your own. - - > Though we ask you to clean your history and squash commit before submitting a pull-request, please do not change any commits you've submitted already (as other work might be build on top). - -## Translations - -Translators can do their work in our [Transifex project](https://www.transifex.com/projects/p/discourse-org/). For more information, please see these how-to topics: - -* [Contributing a translation to Discourse](https://meta.discourse.org/t/contribute-a-translation-to-discourse/14882) -* [How to add a new language](https://meta.discourse.org/t/how-to-add-a-new-language/14970) - - - -[m]: http://meta.discourse.org +*Thanks for contributing!* diff --git a/Gemfile b/Gemfile index e8b2403e5a..2332689189 100644 --- a/Gemfile +++ b/Gemfile @@ -63,7 +63,8 @@ gem 'email_reply_parser' # note: for image_optim to correctly work you need to follow # https://github.com/toy/image_optim -gem 'image_optim' +# pinned due to https://github.com/toy/image_optim/pull/75, docker image must be upgraded to upgrade +gem 'image_optim', '0.20.2' gem 'multi_json' gem 'mustache' gem 'nokogiri' diff --git a/Gemfile.lock b/Gemfile.lock index 338070cfa7..e33b7a10e3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -209,7 +209,7 @@ GEM omniauth-twitter (1.0.1) multi_json (~> 1.3) omniauth-oauth (~> 1.0) - onebox (1.5.24) + onebox (1.5.25) moneta (~> 0.8) multi_json (~> 1.11) mustache @@ -422,7 +422,7 @@ DEPENDENCIES highline hiredis htmlentities - image_optim + image_optim (= 0.20.2) librarian (>= 0.0.25) listen (= 0.7.3) logster @@ -488,3 +488,6 @@ DEPENDENCIES uglifier unf unicorn + +BUNDLED WITH + 1.10.6 diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 b/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 index ab304adc7a..c712a8ac5a 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-dashboard.js.es6 @@ -13,7 +13,7 @@ export default Ember.Controller.extend({ }.property('problems'), thereWereProblems: function() { - if(!Discourse.User.currentProp('admin')) { return false } + if(!Discourse.User.currentProp('admin')) { return false; } if( this.get('foundProblems') ) { this.set('hadProblems', true); return true; diff --git a/app/assets/javascripts/admin/controllers/admin-group.js.es6 b/app/assets/javascripts/admin/controllers/admin-group.js.es6 index f16151ed29..2ee95299a1 100644 --- a/app/assets/javascripts/admin/controllers/admin-group.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-group.js.es6 @@ -39,7 +39,7 @@ export default Ember.Controller.extend({ if (this.get("showingLast")) { return; } const group = this.get("model"), - offset = Math.min(group.get("offset") + group.get("model.limit"), group.get("user_count")); + offset = Math.min(group.get("offset") + group.get("limit"), group.get("user_count")); group.set("offset", offset); @@ -50,7 +50,7 @@ export default Ember.Controller.extend({ if (this.get("showingFirst")) { return; } const group = this.get("model"), - offset = Math.max(group.get("offset") - group.get("model.limit"), 0); + offset = Math.max(group.get("offset") - group.get("limit"), 0); group.set("offset", offset); diff --git a/app/assets/javascripts/admin/controllers/admin-reports.js.es6 b/app/assets/javascripts/admin/controllers/admin-reports.js.es6 index e964d17a25..d11e67305a 100644 --- a/app/assets/javascripts/admin/controllers/admin-reports.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-reports.js.es6 @@ -1,3 +1,6 @@ +import { exportEntity } from 'discourse/lib/export-csv'; +import { outputExportResult } from 'discourse/lib/export-result'; + export default Ember.Controller.extend({ viewMode: 'table', viewingTable: Em.computed.equal('viewMode', 'table'), @@ -30,6 +33,15 @@ export default Ember.Controller.extend({ viewAsBarChart() { this.set('viewMode', 'barChart'); + }, + + exportCsv() { + exportEntity('report', { + name: this.get("model.type"), + start_date: this.get('startDate'), + end_date: this.get('endDate'), + category_id: this.get('categoryId') === 'all' ? undefined : this.get('categoryId') + }).then(outputExportResult); } } }); diff --git a/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 index 2034d10368..74c4f79e6c 100644 --- a/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 @@ -56,8 +56,8 @@ export default Ember.Controller.extend({ saveAll: function(){ var self = this; var items = this.get('workingCopy'); - var groupIds = items.map(function(i){return i.get("id") || -1}); - var names = items.map(function(i){return i.get("name")}); + var groupIds = items.map(function(i){return i.get("id") || -1;}); + var names = items.map(function(i){return i.get("name");}); Discourse.ajax('/admin/badges/badge_groupings',{ data: {ids: groupIds, names: names}, diff --git a/app/assets/javascripts/admin/templates/components/site-settings/bool.hbs b/app/assets/javascripts/admin/templates/components/site-settings/bool.hbs index 1f441c421c..f1ac669900 100644 --- a/app/assets/javascripts/admin/templates/components/site-settings/bool.hbs +++ b/app/assets/javascripts/admin/templates/components/site-settings/bool.hbs @@ -1,4 +1,5 @@ diff --git a/app/assets/javascripts/admin/templates/group.hbs b/app/assets/javascripts/admin/templates/group.hbs index 3da80d9af7..ac1f979691 100644 --- a/app/assets/javascripts/admin/templates/group.hbs +++ b/app/assets/javascripts/admin/templates/group.hbs @@ -13,9 +13,9 @@
- {{fa-icon "fast-backward"}} + {{currentPage}}/{{totalPages}} - {{fa-icon "fast-forward"}} +
{{#each model.members as |member|}} @@ -28,7 +28,7 @@
{{user-selector usernames=model.usernames placeholderKey="admin.groups.selector_placeholder" id="user-selector"}} - + {{d-button action="addMembers" class="add" icon="plus" label="admin.groups.add"}}
{{/unless}} {{/if}} diff --git a/app/assets/javascripts/admin/templates/reports.hbs b/app/assets/javascripts/admin/templates/reports.hbs index c7383ef2c8..718a61a2c1 100644 --- a/app/assets/javascripts/admin/templates/reports.hbs +++ b/app/assets/javascripts/admin/templates/reports.hbs @@ -5,6 +5,7 @@ {{i18n 'admin.dashboard.reports.end_date'}} {{input type="date" value=endDate}} {{combo-box valueAttribute="value" content=categoryOptions value=categoryId}} {{d-button action="refreshReport" class="btn-primary" label="admin.dashboard.reports.refresh_report" icon="refresh"}} + {{d-button action="exportCsv" label="admin.export_csv.button_text" icon="download"}}
diff --git a/app/assets/javascripts/discourse.js b/app/assets/javascripts/discourse.js index 57165d9d26..ebe4da3ee9 100644 --- a/app/assets/javascripts/discourse.js +++ b/app/assets/javascripts/discourse.js @@ -152,10 +152,10 @@ function proxyDep(propName, moduleFunc, msg) { }); } -proxyDep('computed', function() { return require('discourse/lib/computed') }); -proxyDep('Formatter', function() { return require('discourse/lib/formatter') }); -proxyDep('PageTracker', function() { return require('discourse/lib/page-tracker').default }); -proxyDep('URL', function() { return require('discourse/lib/url').default }); -proxyDep('Quote', function() { return require('discourse/lib/quote').default }); -proxyDep('debounce', function() { return require('discourse/lib/debounce').default }); -proxyDep('View', function() { return Ember.View }, "Use `Ember.View` instead"); +proxyDep('computed', function() { return require('discourse/lib/computed'); }); +proxyDep('Formatter', function() { return require('discourse/lib/formatter'); }); +proxyDep('PageTracker', function() { return require('discourse/lib/page-tracker').default; }); +proxyDep('URL', function() { return require('discourse/lib/url').default; }); +proxyDep('Quote', function() { return require('discourse/lib/quote').default; }); +proxyDep('debounce', function() { return require('discourse/lib/debounce').default; }); +proxyDep('View', function() { return Ember.View; }, "Use `Ember.View` instead"); diff --git a/app/assets/javascripts/discourse/components/auto-close-form.js.es6 b/app/assets/javascripts/discourse/components/auto-close-form.js.es6 index 2d564d246d..f6ab041c7c 100644 --- a/app/assets/javascripts/discourse/components/auto-close-form.js.es6 +++ b/app/assets/javascripts/discourse/components/auto-close-form.js.es6 @@ -2,8 +2,8 @@ import computed from "ember-addons/ember-computed-decorators"; import { observes } from "ember-addons/ember-computed-decorators"; export default Ember.Component.extend({ - autoCloseValid: false, limited: false, + autoCloseValid: false, @computed("limited") autoCloseUnits(limited) { @@ -19,15 +19,14 @@ export default Ember.Component.extend({ @observes("autoCloseTime", "limited") _updateAutoCloseValid() { - const autoCloseTime = this.get("autoCloseTime"); - const limited = this.get("limited"); - - var isValid = this._isAutoCloseValid(autoCloseTime, limited); + const limited = this.get("limited"), + autoCloseTime = this.get("autoCloseTime"), + isValid = this._isAutoCloseValid(autoCloseTime, limited); this.set("autoCloseValid", isValid); }, _isAutoCloseValid(autoCloseTime, limited) { - var t = (autoCloseTime || "").toString().trim(); + const t = (autoCloseTime || "").toString().trim(); if (t.length === 0) { // "empty" is always valid return true; diff --git a/app/assets/javascripts/discourse/components/autofocus-text-field.js.es6 b/app/assets/javascripts/discourse/components/autofocus-text-field.js.es6 index 29ecbb0d30..dd1ccd9871 100644 --- a/app/assets/javascripts/discourse/components/autofocus-text-field.js.es6 +++ b/app/assets/javascripts/discourse/components/autofocus-text-field.js.es6 @@ -1,7 +1,12 @@ +import { on } from "ember-addons/ember-computed-decorators"; + export default Ember.TextField.extend({ - becomeFocused: function() { - var input = this.get("element"); + + @on("didInsertElement") + becomeFocused() { + const input = this.get("element"); input.focus(); input.selectionStart = input.selectionEnd = input.value.length; - }.on('didInsertElement') + } + }); diff --git a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 index 8379606460..539171bc9a 100644 --- a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 @@ -1,3 +1,4 @@ +import computed from "ember-addons/ember-computed-decorators"; import UploadMixin from "discourse/mixins/upload"; export default Em.Component.extend(UploadMixin, { @@ -5,21 +6,23 @@ export default Em.Component.extend(UploadMixin, { tagName: "span", imageIsNotASquare: false, - uploadButtonText: function() { - return this.get("uploading") ? I18n.t("uploading") : I18n.t("user.change_avatar.upload_picture"); - }.property("uploading"), + @computed("uploading") + uploadButtonText(uploading) { + return uploading ? I18n.t("uploading") : I18n.t("user.change_avatar.upload_picture"); + }, uploadDone(upload) { this.setProperties({ imageIsNotASquare: upload.width !== upload.height, uploadedAvatarTemplate: upload.url, - custom_avatar_upload_id: upload.id, + uploadedAvatarId: upload.id, }); this.sendAction("done"); }, - data: function() { - return { user_id: this.get("user_id") }; - }.property("user_id") + @computed("user_id") + data(user_id) { + return { user_id }; + } }); diff --git a/app/assets/javascripts/discourse/components/categories-admin-dropdown.js.es6 b/app/assets/javascripts/discourse/components/categories-admin-dropdown.js.es6 new file mode 100644 index 0000000000..b2fea03ffd --- /dev/null +++ b/app/assets/javascripts/discourse/components/categories-admin-dropdown.js.es6 @@ -0,0 +1,39 @@ +import { iconHTML } from 'discourse/helpers/fa-icon'; +import DropdownButton from 'discourse/components/dropdown-button'; +import computed from "ember-addons/ember-computed-decorators"; + +export default DropdownButton.extend({ + buttonExtraClasses: 'no-text', + title: '', + text: iconHTML('bars') + ' ' + iconHTML('caret-down'), + classNames: ['category-notification-menu', 'category-admin-menu'], + + @computed() + dropDownContent() { + const includeReorder = this.get('siteSettings.fixed_category_positions'); + const items = [ + { id: 'create', + title: I18n.t('category.create'), + description: I18n.t('category.create_long'), + styleClasses: 'fa fa-plus' } + ]; + if (includeReorder) { + items.push({ + id: 'reorder', + title: I18n.t('categories.reorder.title'), + description: I18n.t('categories.reorder.title_long'), + styleClasses: 'fa fa-random' + }); + } + return items; + }, + + actionNames: { + create: 'createCategory', + reorder: 'reorderCategories' + }, + + clicked(id) { + this.sendAction('actionNames.' + id); + } +}); diff --git a/app/assets/javascripts/discourse/components/category-drop.js.es6 b/app/assets/javascripts/discourse/components/category-drop.js.es6 index 696991853c..b824117955 100644 --- a/app/assets/javascripts/discourse/components/category-drop.js.es6 +++ b/app/assets/javascripts/discourse/components/category-drop.js.es6 @@ -47,7 +47,7 @@ export default Ember.Component.extend({ if (color) { var style = ""; - if (color) { style += "background-color: #" + color + ";" } + if (color) { style += "background-color: #" + color + ";"; } return style.htmlSafe(); } } diff --git a/app/assets/javascripts/discourse/components/dropdown-button.js.es6 b/app/assets/javascripts/discourse/components/dropdown-button.js.es6 index 99d211bbe3..0037ec17f2 100644 --- a/app/assets/javascripts/discourse/components/dropdown-button.js.es6 +++ b/app/assets/javascripts/discourse/components/dropdown-button.js.es6 @@ -29,9 +29,7 @@ export default Ember.Component.extend(StringBuffer, { buffer.push("

" + title + "

"); } - buffer.push(""); + buffer.push(``); buffer.push(" + {{plugin-outlet "header-before-dropdowns"}} + {{user-menu visible=userMenuVisible logoutAction="logout"}} + {{hamburger-menu visible=hamburgerVisible showKeyboardAction="showKeyboardShortcutsHelp"}} + {{search-menu visible=searchVisible}}
{{#if showExtraInfo}} diff --git a/app/assets/javascripts/discourse/templates/list/post-count-or-badges.raw.hbs b/app/assets/javascripts/discourse/templates/list/post-count-or-badges.raw.hbs new file mode 100644 index 0000000000..88dfe8f000 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/list/post-count-or-badges.raw.hbs @@ -0,0 +1,8 @@ +{{#if view.showBadges}} + {{raw "topic-post-badges" unread=topic.unread newPosts=topic.displayNewPosts unseen=topic.unseen url=topic.lastUnreadUrl}} +{{else}} + {{#if topic.unseen}} + + {{/if}} + {{raw "list/posts-count-column" topic=topic tagName="div"}} +{{/if}} \ No newline at end of file diff --git a/app/assets/javascripts/discourse/templates/list/posters-column.raw.hbs b/app/assets/javascripts/discourse/templates/list/posters-column.raw.hbs index 1b837fb5a7..5adbfd3d72 100644 --- a/app/assets/javascripts/discourse/templates/list/posters-column.raw.hbs +++ b/app/assets/javascripts/discourse/templates/list/posters-column.raw.hbs @@ -1,5 +1,5 @@ {{#each poster in posters}} -{{avatar poster usernamePath="user.username" imageSize="small"}} +{{avatar poster avatarTemplatePath="user.avatar_template" usernamePath="user.username" imageSize="small"}} {{/each}} diff --git a/app/assets/javascripts/discourse/templates/mobile/components/basic-topic-list.hbs b/app/assets/javascripts/discourse/templates/mobile/components/basic-topic-list.hbs index 611d012ccf..06af1df5d1 100644 --- a/app/assets/javascripts/discourse/templates/mobile/components/basic-topic-list.hbs +++ b/app/assets/javascripts/discourse/templates/mobile/components/basic-topic-list.hbs @@ -5,13 +5,9 @@ {{#each t in topics}} -