Merge branch 'release/0.5.0.0-RC'
17
.editorconfig
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
[{Gemfile,Rakefile,Guardfile,Procfile}]
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{js,hbs,rb,rake,ru,erb,haml,scss,sh,md}]
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.yml]
|
||||
trim_trailing_whitespace = false
|
||||
2
.foreman
|
|
@ -1,2 +1,2 @@
|
|||
port: 3000
|
||||
formation: web=1,sidekiq=0
|
||||
formation: xmpp=0,web=1,sidekiq=0
|
||||
|
|
|
|||
14
.gitignore
vendored
|
|
@ -1,3 +1,7 @@
|
|||
# xmpp certificates, keys and user data
|
||||
config/vines/*.crt
|
||||
config/vines/*.key
|
||||
|
||||
#trademark sillyness
|
||||
app/views/home/_show.*
|
||||
app/views/terms/terms.*
|
||||
|
|
@ -10,6 +14,7 @@ config/heroku.yml
|
|||
config/initializers/secret_token.rb
|
||||
config/redis.conf
|
||||
config/deploy_config.yml
|
||||
config/schedule.rb
|
||||
.bundle
|
||||
vendor/bundle/
|
||||
vendor/cache/
|
||||
|
|
@ -29,6 +34,11 @@ spec/fixtures/*.y*ml
|
|||
spec/fixtures/*.fixture.*
|
||||
coverage/
|
||||
xml_locales/
|
||||
public/404.html
|
||||
public/422.html
|
||||
public/500.html
|
||||
|
||||
# Sprites
|
||||
app/assets/images/branding-*.png
|
||||
app/assets/images/icons-*.png
|
||||
app/assets/images/social_media_logos-*.png
|
||||
|
|
@ -58,7 +68,6 @@ tmp/
|
|||
*.swp
|
||||
*~
|
||||
*#
|
||||
bin/*
|
||||
nbproject
|
||||
patches-*
|
||||
capybara-*.html
|
||||
|
|
@ -69,3 +78,6 @@ dump.rdb
|
|||
|
||||
#IDE
|
||||
diaspora.iml
|
||||
|
||||
# Dolphin's directory's preferences files
|
||||
*.directory
|
||||
|
|
|
|||
9
.hound.yml
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
java_script:
|
||||
enabled: true
|
||||
config_file: config/.jshint.json
|
||||
ignore_file: config/.jshint_ignore
|
||||
ruby:
|
||||
enabled: true
|
||||
config_file: .rubocop.yml
|
||||
scss:
|
||||
enabled: false
|
||||
1
.jshintignore
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
config/.jshint_ignore
|
||||
1
.jshintrc
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
config/.jshint.json
|
||||
15
.pairs
|
|
@ -1,15 +0,0 @@
|
|||
pairs:
|
||||
dg: Daniel Grippi; daniel
|
||||
rs: Raphael Sofaer; raphael
|
||||
iz: Ilya Zhitomirskiy; ilya
|
||||
ms: Maxwell Salzberg; maxwell
|
||||
dh: Dan Hansen; ohaibbq
|
||||
sm: Sarah Mei; sarah
|
||||
mjs: Michael Sofaer; michael
|
||||
jd: Jeff Dickey; dickeytk
|
||||
dc: Dennis Collinson
|
||||
tf: Tim Frazer
|
||||
kf: Kevin Fitzpatrick
|
||||
email:
|
||||
prefix: pair
|
||||
domain: joindiaspora.com
|
||||
1
.powenv
|
|
@ -1 +0,0 @@
|
|||
export NEW_HOTNESS=yessir
|
||||
4
.powrc
|
|
@ -1,4 +0,0 @@
|
|||
if [ -f "$rvm_path/scripts/rvm" ] && [ -f ".rvmrc" ]; then
|
||||
source "$rvm_path/scripts/rvm"
|
||||
source ".rvmrc"
|
||||
fi
|
||||
1
.rspec
|
|
@ -3,4 +3,3 @@
|
|||
--color
|
||||
--tag ~performance
|
||||
--order random
|
||||
--drb
|
||||
|
|
|
|||
130
.rubocop.yml
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
AllCops:
|
||||
RunRailsCops: true
|
||||
|
||||
# Commonly used screens these days easily fit more than 80 characters.
|
||||
Metrics/LineLength:
|
||||
Max: 120
|
||||
|
||||
# Too short methods lead to extraction of single-use methods, which can make
|
||||
# the code easier to read (by naming things), but can also clutter the class
|
||||
Metrics/MethodLength:
|
||||
Max: 20
|
||||
|
||||
# The guiding principle of classes is SRP, SRP can't be accurately measured by LoC
|
||||
Metrics/ClassLength:
|
||||
Max: 1500
|
||||
|
||||
# No space makes the method definition shorter and differentiates
|
||||
# from a regular assignment.
|
||||
Style/SpaceAroundEqualsInParameterDefault:
|
||||
EnforcedStyle: no_space
|
||||
|
||||
# Single quotes being faster is hardly measurable and only affects parse time.
|
||||
# Enforcing double quotes reduces the times where you need to change them
|
||||
# when introducing an interpolation. Use single quotes only if their semantics
|
||||
# are needed.
|
||||
Style/StringLiterals:
|
||||
EnforcedStyle: double_quotes
|
||||
|
||||
# We do not need to support Ruby 1.9, so this is good to use.
|
||||
Style/SymbolArray:
|
||||
Enabled: true
|
||||
|
||||
# Most readable form.
|
||||
Style/AlignHash:
|
||||
EnforcedHashRocketStyle: table
|
||||
EnforcedColonStyle: table
|
||||
|
||||
# Mixing the styles looks just silly.
|
||||
# REVIEW: Enable once https://github.com/bbatsov/rubocop/commit/760ce1ed2cf10beda5e163f934c03a6fb6daa38e
|
||||
# is released.
|
||||
#Style/HashSyntax:
|
||||
# EnforcedStyle: ruby19_no_mixed_keys
|
||||
|
||||
# has_key? and has_value? are far more readable than key? and value?
|
||||
Style/DeprecatedHashMethods:
|
||||
Enabled: false
|
||||
|
||||
# String#% is by far the least verbose and only object oriented variant.
|
||||
Style/FormatString:
|
||||
EnforcedStyle: percent
|
||||
|
||||
Style/CollectionMethods:
|
||||
Enabled: true
|
||||
PreferredMethods:
|
||||
# inject seems more common in the community.
|
||||
reduce: "inject"
|
||||
|
||||
|
||||
# Either allow this style or don't. Marking it as safe with parenthesis
|
||||
# is silly. Let's try to live without them for now.
|
||||
Style/ParenthesesAroundCondition:
|
||||
AllowSafeAssignment: false
|
||||
Lint/AssignmentInCondition:
|
||||
AllowSafeAssignment: false
|
||||
|
||||
# A specialized exception class will take one or more arguments and construct the message from it.
|
||||
# So both variants make sense.
|
||||
Style/RaiseArgs:
|
||||
Enabled: false
|
||||
|
||||
# Fail is an alias of raise. Avoid aliases, it's more cognitive load for no gain.
|
||||
# The argument that fail should be used to abort the program is wrong too,
|
||||
# there's Kernel#abort for that.
|
||||
Style/SignalException:
|
||||
EnforcedStyle: only_raise
|
||||
|
||||
# Suppressing exceptions can be perfectly fine, and be it to avoid to
|
||||
# explicitly type nil into the rescue since that's what you want to return,
|
||||
# or suppressing LoadError for optional dependencies
|
||||
Lint/HandleExceptions:
|
||||
Enabled: false
|
||||
|
||||
Style/SpaceInsideBlockBraces:
|
||||
# The space here provides no real gain in readability while consuming
|
||||
# horizontal space that could be used for a better parameter name.
|
||||
# Also {| differentiates better from a hash than { | does.
|
||||
SpaceBeforeBlockParameters: false
|
||||
|
||||
# No trailing space differentiates better from the block:
|
||||
# foo} means hash, foo } means block.
|
||||
Style/SpaceInsideHashLiteralBraces:
|
||||
EnforcedStyle: no_space
|
||||
|
||||
# { ... } for multi-line blocks is okay, follow Weirichs rule instead:
|
||||
# https://web.archive.org/web/20140221124509/http://onestepback.org/index.cgi/Tech/Ruby/BraceVsDoEnd.rdoc
|
||||
Style/Blocks:
|
||||
Enabled: false
|
||||
|
||||
# do / end blocks should be used for side effects,
|
||||
# methods that run a block for side effects and have
|
||||
# a useful return value are rare, assign the return
|
||||
# value to a local variable for those cases.
|
||||
Style/MethodCalledOnDoEndBlock:
|
||||
Enabled: true
|
||||
|
||||
# Enforcing the names of variables? To single letter ones? Just no.
|
||||
Style/SingleLineBlockParams:
|
||||
Enabled: false
|
||||
|
||||
# Shadowing outer local variables with block parameters is often useful
|
||||
# to not reinvent a new name for the same thing, it highlights the relation
|
||||
# between the outer variable and the parameter. The cases where it's actually
|
||||
# confusing are rare, and usually bad for other reasons already, for example
|
||||
# because the method is too long.
|
||||
Lint/ShadowingOuterLocalVariable:
|
||||
Enabled: false
|
||||
|
||||
# Check with yard instead.
|
||||
Style/Documentation:
|
||||
Enabled: false
|
||||
|
||||
# This is just silly. Calling the argument `other` in all cases makes no sense.
|
||||
Style/OpMethod:
|
||||
Enabled: false
|
||||
|
||||
# There are valid cases, for example debugging Cucumber steps,
|
||||
# also they'll fail CI anyway
|
||||
Lint/Debugger:
|
||||
Enabled: false
|
||||
|
||||
|
|
@ -1 +1 @@
|
|||
2.0
|
||||
2.1
|
||||
|
|
|
|||
27
.travis.yml
|
|
@ -1,12 +1,8 @@
|
|||
branches:
|
||||
only:
|
||||
- 'master'
|
||||
- 'develop'
|
||||
|
||||
language: ruby
|
||||
|
||||
rvm:
|
||||
- 2.0.0
|
||||
- 1.9.3
|
||||
- 2.1
|
||||
- 2.0
|
||||
|
||||
env:
|
||||
- DB=postgres BUILD_TYPE=other
|
||||
|
|
@ -14,13 +10,22 @@ env:
|
|||
- DB=postgres BUILD_TYPE=cucumber
|
||||
- DB=mysql BUILD_TYPE=cucumber
|
||||
|
||||
sudo: false
|
||||
cache:
|
||||
bundler: true
|
||||
directories:
|
||||
- app/assets/images
|
||||
|
||||
branches:
|
||||
only:
|
||||
- 'master'
|
||||
- 'develop'
|
||||
|
||||
before_install: gem install bundler
|
||||
bundler_args: "--without development production heroku --jobs 3 --retry 3"
|
||||
|
||||
bundler_args: "--without development production heroku"
|
||||
script: "./script/ci/build.sh"
|
||||
|
||||
addons:
|
||||
firefox: "26.0"
|
||||
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
|
|
|
|||
223
Changelog.md
|
|
@ -1,3 +1,219 @@
|
|||
# 0.5.0.0
|
||||
|
||||
## Major Sidekiq update
|
||||
This release includes a major upgrade of the background processing system Sidekiq. To upgrade cleanly:
|
||||
|
||||
1. Stop diaspora*
|
||||
2. Run `RAILS_ENV=production bundle exec sidekiq` and wait 5-10 minutes, then stop it again (hit `CTRL+C`)
|
||||
3. Do a normal upgrade of diaspora*
|
||||
4. Start diaspora*
|
||||
|
||||
## Rails 4 - Manual action required
|
||||
Please edit `config/initializers/secret_token.rb`, replacing `secret_token` with
|
||||
`secret_key_base`.
|
||||
|
||||
```ruby
|
||||
# Old
|
||||
Rails.application.config.secret_token = '***********...'
|
||||
|
||||
# New
|
||||
Diaspora::Application.config.secret_key_base = '*************...'
|
||||
```
|
||||
|
||||
You also need to take care to set `RAILS_ENV` and to clear the cache while precompiling assets: `RAILS_ENV=production bundle exec rake tmp:cache:clear assets:precompile`
|
||||
|
||||
## Supported Ruby versions
|
||||
This release drops official support for the Ruby 1.9 series. This means we will no longer test against this Ruby version or take care to choose libraries
|
||||
that work with it. However that doesn't mean we won't accept patches that improve running diaspora* on it.
|
||||
|
||||
At the same time we adopt support for the Ruby 2.1 series and recommend running on the latest Ruby version of that branch. We continue to support the Ruby 2.0
|
||||
series and run our comprehensive test suite against it.
|
||||
|
||||
## Change in defaults.yml
|
||||
The default for including jQuery from a CDN has changed. If you want to continue to include it from a CDN, please explicitly set the `jquery_cdn` setting to `true` in diaspora.yml.
|
||||
|
||||
## Change in database.yml
|
||||
For MySQL databases, replace `charset: utf8` with `encoding: utf8mb4` and change `collation` from `utf8_bin` to `utf8mb4_bin` in the file `config/database.yml`.
|
||||
This is enables full UTF8 support (4bytes characters), including standard emoji characters.
|
||||
See `database.yml.example` for reference.
|
||||
Please make sure to stop Diaspora prior running this migration!
|
||||
|
||||
## Experimental chat feature
|
||||
This release adds experimental integration with XMPP for real-time chat. Please see [our wiki](https://wiki.diasporafoundation.org/Vines) for further informations.
|
||||
|
||||
## Change in statistics.json schema
|
||||
The way services are shown in the `statistics.json` route is changing. The keys relating to showing whether services are enabled or not are moving to their own container as `"services": {....}`, instead of having them all in the root level of the JSON.
|
||||
|
||||
The keys will still be available in the root level within the 0.5 release. The old keys will be removed in the 0.6 release.
|
||||
|
||||
## New maintenance feature to automatically expire inactive accounts
|
||||
Removing of old inactive users can now be done automatically by background processing. The amount of inactivity is set by `after_days`. A warning email will be sent to the user and after an additional `warn_days`, the account will be automatically closed.
|
||||
|
||||
This maintenance is not enabled by default. Podmins can enable it by for example copying over the new settings under `settings.maintenance` to their `diaspora.yml` file and setting it enabled. The default setting is to expire accounts that have been inactive for 2 years (no login).
|
||||
|
||||
## Camo integration to proxy external assets
|
||||
It is now possible to enable an automatic proxying of external assets, for example images embedded via Markdown or OpenGraph thumbnails loaded from insecure third party servers through a [Camo proxy](https://github.com/atmos/camo).
|
||||
|
||||
This is disabled by default since it requires the installation of additional packages and might cause some traffic. Check the [wiki page](https://wiki.diasporafoundation.org/Installation/Camo) for more information and detailed installation instructions.
|
||||
|
||||
## Paypal unhosted button and currency
|
||||
Podmins can now set the currency for donations, and use an unhosted button if they can't use
|
||||
a hosted one. Note: you need to **copy the new settings from diaspora.yml.example to your
|
||||
diaspora.yml file**. The existing settings from 0.4.x and before will not work any more.
|
||||
|
||||
## Custom splash page changes
|
||||
diaspora* no longer adds a `div.container` to wrap custom splash pages. This adds the ability for podmins to write home pages using Bootstrap's fluid design. Podmins who added a custom splash page in `app/views/home/_show.{html,mobile}.haml` need to wrap the contents into a `div.container` to keep the old design. You will find updated examples [in our wiki](https://wiki.diasporafoundation.org/Custom_splash_page).
|
||||
|
||||
## Refactor
|
||||
* Redesign contacts page [#5153](https://github.com/diaspora/diaspora/pull/5153)
|
||||
* Improve profile page design on mobile [#5084](https://github.com/diaspora/diaspora/pull/5084)
|
||||
* Port test suite to RSpec 3 [#5170](https://github.com/diaspora/diaspora/pull/5170)
|
||||
* Port tag stream to Bootstrap [#5138](https://github.com/diaspora/diaspora/pull/5138)
|
||||
* Consolidate migrations, if you need a migration prior 2013, checkout the latest release in the 0.4.x series first [#5173](https://github.com/diaspora/diaspora/pull/5173)
|
||||
* Add tests for mobile sign up [#5185](https://github.com/diaspora/diaspora/pull/5185)
|
||||
* Display new conversation form on conversations/index [#5178](https://github.com/diaspora/diaspora/pull/5178)
|
||||
* Port profile page to Backbone [#5180](https://github.com/diaspora/diaspora/pull/5180)
|
||||
* Pull punycode.js from rails-assets.org [#5263](https://github.com/diaspora/diaspora/pull/5263)
|
||||
* Redesign profile page and port to Bootstrap [#4657](https://github.com/diaspora/diaspora/pull/4657)
|
||||
* Unify stream selection links in the left sidebar [#5271](https://github.com/diaspora/diaspora/pull/5271)
|
||||
* Refactor schema of statistics.json regarding services [#5296](https://github.com/diaspora/diaspora/pull/5296)
|
||||
* Pull jquery.idle-timer.js from rails-assets.org [#5310](https://github.com/diaspora/diaspora/pull/5310)
|
||||
* Pull jquery.placeholder.js from rails-assets.org [#5299](https://github.com/diaspora/diaspora/pull/5299)
|
||||
* Pull jquery.textchange.js from rails-assets.org [#5297](https://github.com/diaspora/diaspora/pull/5297)
|
||||
* Pull jquery.hotkeys.js from rails-assets.org [#5368](https://github.com/diaspora/diaspora/pull/5368)
|
||||
* Reduce amount of useless background job retries and pull public posts when missing [#5209](https://github.com/diaspora/diaspora/pull/5209)
|
||||
* Updated Weekly User Stats admin page to show data for the most recent week including reversing the order of the weeks in the drop down to show the most recent. [#5331](https://github.com/diaspora/diaspora/pull/5331)
|
||||
* Convert some cukes to RSpec tests [#5289](https://github.com/diaspora/diaspora/pull/5289)
|
||||
* Hidden overflow for long names on tag pages [#5279](https://github.com/diaspora/diaspora/pull/5279)
|
||||
* Always reshare absolute root of a post [#5276](https://github.com/diaspora/diaspora/pull/5276)
|
||||
* Convert remaining SASS stylesheets to SCSS [#5342](https://github.com/diaspora/diaspora/pull/5342)
|
||||
* Update rack-protection [#5403](https://github.com/diaspora/diaspora/pull/5403)
|
||||
* Cleanup diaspora.yml [#5426](https://github.com/diaspora/diaspora/pull/5426)
|
||||
* Replace `opengraph_parser` with `open_graph_reader` [#5462](https://github.com/diaspora/diaspora/pull/5462)
|
||||
* Make sure conversations without any visibilities left are deleted [#5478](https://github.com/diaspora/diaspora/pull/5478)
|
||||
* Change tooltip for delete button in conversations view [#5477](https://github.com/diaspora/diaspora/pull/5477)
|
||||
* Replace a modifier-rescue with a specific rescue [#5491](https://github.com/diaspora/diaspora/pull/5491)
|
||||
* Port contacts page to backbone [#5473](https://github.com/diaspora/diaspora/pull/5473)
|
||||
* Replace CSS vendor prefixes automatically [#5532](https://github.com/diaspora/diaspora/pull/5532)
|
||||
* Use sentence case consistently throughout UI [#5588](https://github.com/diaspora/diaspora/pull/5588)
|
||||
* Hide sign up button when registrations are disabled [#5612](https://github.com/diaspora/diaspora/pull/5612)
|
||||
* Standardize capitalization throughout the UI [#5588](https://github.com/diaspora/diaspora/pull/5588)
|
||||
* Display photos on the profile page as thumbnails [#5521](https://github.com/diaspora/diaspora/pull/5521)
|
||||
* Unify not connected pages (sign in, sign up, forgot password) [#5391](https://github.com/diaspora/diaspora/pull/5391)
|
||||
* Port remaining stream pages to Bootstrap [#5715](https://github.com/diaspora/diaspora/pull/5715)
|
||||
* Port notification dropdown to Backbone [#5707](https://github.com/diaspora/diaspora/pull/5707) [#5761](https://github.com/diaspora/diaspora/pull/5761)
|
||||
* Add rounded corners for avatars [#5733](https://github.com/diaspora/diaspora/pull/5733)
|
||||
* Move registration form to a partial [#5764](https://github.com/diaspora/diaspora/pull/5764)
|
||||
* Add tests for liking and unliking posts [#5741](https://github.com/diaspora/diaspora/pull/5741)
|
||||
* Rewrite slide effect in conversations as css transition for better performance [#5776](https://github.com/diaspora/diaspora/pull/5776)
|
||||
* Various cleanups and improvements in the frontend code [#5781](https://github.com/diaspora/diaspora/pull/5781) [#5769](https://github.com/diaspora/diaspora/pull/5769) [#5763](https://github.com/diaspora/diaspora/pull/5763) [#5762](https://github.com/diaspora/diaspora/pull/5762) [#5758](https://github.com/diaspora/diaspora/pull/5758) [#5755](https://github.com/diaspora/diaspora/pull/5755) [#5747](https://github.com/diaspora/diaspora/pull/5747) [#5734](https://github.com/diaspora/diaspora/pull/5734) [#5786](https://github.com/diaspora/diaspora/pull/5786) [#5768](https://github.com/diaspora/diaspora/pull/5798)
|
||||
* Add specs and validations to the role model [#5792](https://github.com/diaspora/diaspora/pull/5792)
|
||||
* Replace 'Make something' text by diaspora ball logo on registration page [#5743](https://github.com/diaspora/diaspora/pull/5743)
|
||||
|
||||
## Bug fixes
|
||||
* orca cannot see 'Add Contact' button [#5158](https://github.com/diaspora/diaspora/pull/5158)
|
||||
* Move submit button to the right in conversations view [#4960](https://github.com/diaspora/diaspora/pull/4960)
|
||||
* Handle long URLs and titles in OpenGraph descriptions [#5208](https://github.com/diaspora/diaspora/pull/5208)
|
||||
* Fix deformed getting started popover [#5227](https://github.com/diaspora/diaspora/pull/5227)
|
||||
* Use correct locale for invitation subject [#5232](https://github.com/diaspora/diaspora/pull/5232)
|
||||
* Initial support for IDN emails
|
||||
* Fix services settings reported by statistics.json [#5256](https://github.com/diaspora/diaspora/pull/5256)
|
||||
* Only collapse empty comment box [#5328](https://github.com/diaspora/diaspora/pull/5328)
|
||||
* Fix pagination for people/guid/contacts [#5304](https://github.com/diaspora/diaspora/pull/5304)
|
||||
* Fix poll creation on Bootstrap pages [#5334](https://github.com/diaspora/diaspora/pull/5334)
|
||||
* Show error message on invalid reset password attempt [#5325](https://github.com/diaspora/diaspora/pull/5325)
|
||||
* Fix translations on mobile password reset pages [#5318](https://github.com/diaspora/diaspora/pull/5318)
|
||||
* Handle unset user agent when signing out [#5316](https://github.com/diaspora/diaspora/pull/5316)
|
||||
* More robust URL parsing for oEmbed and OpenGraph [#5347](https://github.com/diaspora/diaspora/pull/5347)
|
||||
* Fix Publisher doesn't expand while uploading images [#3098](https://github.com/diaspora/diaspora/issues/3098)
|
||||
* Drop unneeded and too open crossdomain.xml
|
||||
* Fix hidden aspect dropdown on getting started page [#5407](https://github.com/diaspora/diaspora/pulls/5407)
|
||||
* Fix a few issues on Bootstrap pages [#5401](https://github.com/diaspora/diaspora/pull/5401)
|
||||
* Improve handling of the `more` link on mobile stream pages [#5400](https://github.com/diaspora/diaspora/pull/5400)
|
||||
* Fix prefilling publisher after getting started [#5442](https://github.com/diaspora/diaspora/pull/5442)
|
||||
* Fix overflow in profile sidebar [#5450](https://github.com/diaspora/diaspora/pull/5450)
|
||||
* Fix code overflow in SPV and improve styling for code tags [#5422](https://github.com/diaspora/diaspora/pull/5422)
|
||||
* Correctly validate if local recipients actually want to receive a conversation [#5449](https://github.com/diaspora/diaspora/pull/5449)
|
||||
* Improve consistency of poll answer ordering [#5471](https://github.com/diaspora/diaspora/pull/5471)
|
||||
* Fix broken aspect selectbox on asynchronous search results [#5488](https://github.com/diaspora/diaspora/pull/5488)
|
||||
* Replace %{third_party_tools} by the appropriate hyperlink in tags FAQ [#5509](https://github.com/diaspora/diaspora/pull/5509)
|
||||
* Repair downloading the profile image from Facebook [#5493](https://github.com/diaspora/diaspora/pull/5493)
|
||||
* Fix localization of post and comment timestamps on mobile [#5482](https://github.com/diaspora/diaspora/issues/5482)
|
||||
* Fix mobile JS loading to quieten errors. Fixes also service buttons on mobile bookmarklet.
|
||||
* Don't error out when adding a too long location to the profile [#5614](https://github.com/diaspora/diaspora/pull/5614)
|
||||
* Correctly decrease unread count for conversations [#5646](https://github.com/diaspora/diaspora/pull/5646)
|
||||
* Fix automatic scroll for conversations [#5646](https://github.com/diaspora/diaspora/pull/5646)
|
||||
* Fix missing translation on privacy settings page [#5671](https://github.com/diaspora/diaspora/pull/5671)
|
||||
* Fix code overflow for the mobile website [#5675](https://github.com/diaspora/diaspora/pull/5675)
|
||||
* Strip Unicode format characters prior post processing [#5680](https://github.com/diaspora/diaspora/pull/5680)
|
||||
* Disable email notifications for closed user accounts [#5640](https://github.com/diaspora/diaspora/pull/5640)
|
||||
* Total user statistic no longer includes closed accounts [#5041](https://github.com/diaspora/diaspora/pull/5041)
|
||||
* Don't add a space when rendering a mention [#5711](https://github.com/diaspora/diaspora/pull/5711)
|
||||
* Fix flickering hovercards [#5714](https://github.com/diaspora/diaspora/pull/5714) [#5876](https://github.com/diaspora/diaspora/pull/5876)
|
||||
* Improved stripping markdown in post titles [#5730](https://github.com/diaspora/diaspora/pull/5730)
|
||||
* Remove border from reply form for conversations [#5744](https://github.com/diaspora/diaspora/pull/5744)
|
||||
* Fix overflow for headings, blockquotes and other elements [#5731](https://github.com/diaspora/diaspora/pull/5731)
|
||||
* Correct photo count on profile page [#5751](https://github.com/diaspora/diaspora/pull/5751)
|
||||
* Fix mobile sign up from an invitation [#5754](https://github.com/diaspora/diaspora/pull/5754)
|
||||
* Set max-width for tag following button on tag page [#5752](https://github.com/diaspora/diaspora/pull/5752)
|
||||
* Display error messages for failed password change [#5580](https://github.com/diaspora/diaspora/pull/5580)
|
||||
* Display correct error message for too long tags [#5783](https://github.com/diaspora/diaspora/pull/5783)
|
||||
* Fix displaying reshares in the stream on mobile [#5790](https://github.com/diaspora/diaspora/pull/5790)
|
||||
* Remove bottom margin from lists that are the last element of a post. [#5721](https://github.com/diaspora/diaspora/pull/5721)
|
||||
* Fix pagination design on conversations page [#5791](https://github.com/diaspora/diaspora/pull/5791)
|
||||
* Prevent inserting posts into the wrong stream [#5838](https://github.com/diaspora/diaspora/pull/5838)
|
||||
* Update help section [#5857](https://github.com/diaspora/diaspora/pull/5857) [#5859](https://github.com/diaspora/diaspora/pull/5859)
|
||||
* Fix asset precompilation check in script/server [#5863](https://github.com/diaspora/diaspora/pull/5863)
|
||||
* Convert MySQL databases to utf8mb4 [#5530](https://github.com/diaspora/diaspora/pull/5530) [#5624](https://github.com/diaspora/diaspora/pull/5624) [#5865](https://github.com/diaspora/diaspora/pull/5865)
|
||||
* Don't upcase labels on mobile sign up/sign in [#5872](https://github.com/diaspora/diaspora/pull/5872)
|
||||
|
||||
## Features
|
||||
* Don't pull jQuery from a CDN by default [#5105](https://github.com/diaspora/diaspora/pull/5105)
|
||||
* Better character limit message [#5151](https://github.com/diaspora/diaspora/pull/5151)
|
||||
* Remember whether a AccountDeletion was performed [#5156](https://github.com/diaspora/diaspora/pull/5156)
|
||||
* Increased the number of notifications shown in drop down bar to 15 [#5129](https://github.com/diaspora/diaspora/pull/5129)
|
||||
* Increase possible captcha length [#5169](https://github.com/diaspora/diaspora/pull/5169)
|
||||
* Display visibility icon in publisher aspects dropdown [#4982](https://github.com/diaspora/diaspora/pull/4982)
|
||||
* Add a link to the reported comment in the admin panel [#5337](https://github.com/diaspora/diaspora/pull/5337)
|
||||
* Strip search query from leading and trailing whitespace [#5317](https://github.com/diaspora/diaspora/pull/5317)
|
||||
* Add the "network" key to statistics.json and set it to "Diaspora" [#5308](https://github.com/diaspora/diaspora/pull/5308)
|
||||
* Infinite scrolling in the notifications dropdown [#5237](https://github.com/diaspora/diaspora/pull/5237)
|
||||
* Maintenance feature to automatically expire inactive accounts [#5288](https://github.com/diaspora/diaspora/pull/5288)
|
||||
* Add LibreJS markers to JavaScript [5320](https://github.com/diaspora/diaspora/pull/5320)
|
||||
* Ask for confirmation when leaving a submittable publisher [#5309](https://github.com/diaspora/diaspora/pull/5309)
|
||||
* Allow page-specific styling via individual CSS classes [#5282](https://github.com/diaspora/diaspora/pull/5282)
|
||||
* Change diaspora logo in the header on hover [#5355](https://github.com/diaspora/diaspora/pull/5355)
|
||||
* Display diaspora handle in search results [#5419](https://github.com/diaspora/diaspora/pull/5419)
|
||||
* Show a message on the ignored users page when there are none [#5434](https://github.com/diaspora/diaspora/pull/5434)
|
||||
* Truncate too long OpenGraph descriptions [#5387](https://github.com/diaspora/diaspora/pull/5387)
|
||||
* Make the source code URL configurable [#5410](https://github.com/diaspora/diaspora/pull/5410)
|
||||
* Prefill publisher on the tag pages [#5442](https://github.com/diaspora/diaspora/pull/5442)
|
||||
* Don't include the content of non-public posts into notification mails [#5494](https://github.com/diaspora/diaspora/pull/5494)
|
||||
* Allow to set unhosted button and currency for paypal donation [#5452](https://github.com/diaspora/diaspora/pull/5452)
|
||||
* Add followed tags in the mobile menu [#5468](https://github.com/diaspora/diaspora/pull/5468)
|
||||
* Replace Pagedown with markdown-it [#5526](https://github.com/diaspora/diaspora/pull/5526)
|
||||
* Do not truncate notification emails anymore [#4342](https://github.com/diaspora/diaspora/issues/4342)
|
||||
* Allows users to export their data in gzipped JSON format from their user settings page [#5499](https://github.com/diaspora/diaspora/pull/5499)
|
||||
* Strip EXIF data from newly uploaded images [#5510](https://github.com/diaspora/diaspora/pull/5510)
|
||||
* Hide user setting if the community spotlight is not enabled on the pod [#5562](https://github.com/diaspora/diaspora/pull/5562)
|
||||
* Add HTML view for pod statistics [#5464](https://github.com/diaspora/diaspora/pull/5464)
|
||||
* Added/Moved hide, block user, report and delete button in SPV [#5547](https://github.com/diaspora/diaspora/pull/5547)
|
||||
* Added keyboard shortcuts r(reshare), m(expand Post), o(open first link in post) [#5602](https://github.com/diaspora/diaspora/pull/5602)
|
||||
* Added dropdown to add/remove people from/to aspects in mobile view [#5594](https://github.com/diaspora/diaspora/pull/5594)
|
||||
* Dynamically compute minimum and maximum valid year for birthday field [#5639](https://github.com/diaspora/diaspora/pull/5639)
|
||||
* Show hovercard on mentions [#5652](https://github.com/diaspora/diaspora/pull/5652)
|
||||
* Make help sections linkable [#5667](https://github.com/diaspora/diaspora/pull/5667)
|
||||
* Add invitation link to contacts page [#5655](https://github.com/diaspora/diaspora/pull/5655)
|
||||
* Add year to notifications page [#5676](https://github.com/diaspora/diaspora/pull/5676)
|
||||
* Give admins the ability to lock & unlock accounts [#5643](https://github.com/diaspora/diaspora/pull/5643)
|
||||
* Add reshares to the stream view immediately [#5699](https://github.com/diaspora/diaspora/pull/5699)
|
||||
* Update and improve help section [#5665](https://github.com/diaspora/diaspora/pull/5665), [#5706](https://github.com/diaspora/diaspora/pull/5706)
|
||||
* Expose participation controls in the stream view [#5511](https://github.com/diaspora/diaspora/pull/5511)
|
||||
* Reimplement photo export [#5685](https://github.com/diaspora/diaspora/pull/5685)
|
||||
* Add participation controls in the single post view [#5722](https://github.com/diaspora/diaspora/pull/5722)
|
||||
* Display polls on reshares [#5782](https://github.com/diaspora/diaspora/pull/5782)
|
||||
* Remove footer from stream pages [#5816](https://github.com/diaspora/diaspora/pull/5816)
|
||||
|
||||
# 0.4.1.3
|
||||
|
||||
* Update Redcarped, fixes [OSVDB-120415](http://osvdb.org/show/osvdb/120415).
|
||||
|
|
@ -19,7 +235,7 @@ This release brings a new ToS feature that allows pods to easily display to user
|
|||
terms:
|
||||
enable: true
|
||||
|
||||
When enabled, the footer and sidebar will have a link to terms page, and signup will have a disclaimer indicating that creating an account means the user accepts the terms of use.
|
||||
When enabled, the footer and sidebar will have a link to terms page, and sign up will have a disclaimer indicating that creating an account means the user accepts the terms of use.
|
||||
|
||||
While the project itself doesn't restrict what kind of terms pods run on, we realize not all podmins want to spend time writing them from scratch. Thus there is a basic ToS template included that will be used unless a custom one available.
|
||||
|
||||
|
|
@ -134,7 +350,7 @@ Read more in [#4249](https://github.com/diaspora/diaspora/pull/4249) and [#4883]
|
|||
* Reorder and reword items on user settings page [#4912](https://github.com/diaspora/diaspora/pull/4912)
|
||||
* SPV: Improve padding and interaction counts [#4426](https://github.com/diaspora/diaspora/pull/4426)
|
||||
* Remove auto 'mark as read' for notifications [#4810](https://github.com/diaspora/diaspora/pull/4810)
|
||||
* Improve set read/unread in notifications dropdown [#4869](https://github.com/diaspora/diaspora/pull/4869)
|
||||
* Improve set read/unread in notifications dropdown [#4869](https://github.com/diaspora/diaspora/pull/4869)
|
||||
* Refactor publisher: trigger events for certain actions, introduce 'disabled' state [#4932](https://github.com/diaspora/diaspora/pull/4932)
|
||||
|
||||
## Bug fixes
|
||||
|
|
@ -1022,7 +1238,7 @@ The new configuration system allows all possible settings to be overriden by env
|
|||
|
||||
### Environment variable changes:
|
||||
|
||||
#### deprectated
|
||||
#### deprecated
|
||||
|
||||
* REDISTOGO_URL in favour of REDIS_URL or ENVIRONMENT_REDIS
|
||||
|
||||
|
|
@ -1081,4 +1297,3 @@ The single-post view will also be revamped/reverted, but that didn't make it int
|
|||
|
||||
|
||||
## Cleanup in maintenance scripts and automated build environment
|
||||
|
||||
|
|
|
|||
285
Gemfile
|
|
@ -1,218 +1,275 @@
|
|||
source 'https://rubygems.org'
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem 'rails', '3.2.20'
|
||||
gem "rails", "4.2.1"
|
||||
|
||||
# Legacy Rails features, remove me!
|
||||
|
||||
# caches_page
|
||||
gem "actionpack-action_caching"
|
||||
gem "actionpack-page_caching"
|
||||
|
||||
# responders (class level)
|
||||
gem "responders", "2.1.0"
|
||||
|
||||
# Appserver
|
||||
|
||||
gem 'unicorn', '4.8.3', :require => false
|
||||
gem "unicorn", "4.8.3", require: false
|
||||
|
||||
# API and JSON
|
||||
|
||||
gem 'acts_as_api', '0.4.2'
|
||||
gem 'json', '1.8.1'
|
||||
gem "acts_as_api", "0.4.2"
|
||||
gem "json", "1.8.2"
|
||||
|
||||
# Authentication
|
||||
|
||||
gem 'devise', '3.2.4'
|
||||
gem 'devise_lastseenable', '0.0.4'
|
||||
gem "devise", "3.4.1"
|
||||
gem "devise_lastseenable", "0.0.4"
|
||||
gem "devise-token_authenticatable", "~> 0.3.0"
|
||||
|
||||
# Captcha
|
||||
|
||||
gem 'galetahub-simple_captcha', '0.1.5', :require => 'simple_captcha'
|
||||
gem "simple_captcha2", "0.3.4", require: "simple_captcha"
|
||||
|
||||
# Background processing
|
||||
|
||||
gem 'sidekiq', '2.17.7'
|
||||
gem 'sinatra', '1.3.3'
|
||||
gem "sidekiq", "3.3.3"
|
||||
gem "sinatra", "1.4.6"
|
||||
|
||||
# Scheduled processing
|
||||
|
||||
gem "sidetiq", "0.6.3"
|
||||
|
||||
# Compression
|
||||
|
||||
gem "uglifier", "2.7.1"
|
||||
|
||||
# Configuration
|
||||
|
||||
gem 'configurate', '0.0.8'
|
||||
gem "configurate", "0.2.0"
|
||||
|
||||
# Cross-origin resource sharing
|
||||
|
||||
gem 'rack-cors', '0.2.9', :require => 'rack/cors'
|
||||
gem "rack-cors", "0.3.1", require: "rack/cors"
|
||||
|
||||
# CSS
|
||||
|
||||
gem "bootstrap-sass", "2.3.2.2"
|
||||
gem "compass-rails", "2.0.4"
|
||||
gem "sass-rails", "5.0.1"
|
||||
gem "autoprefixer-rails", "5.1.7.1"
|
||||
|
||||
# Database
|
||||
|
||||
ENV['DB'] ||= 'mysql'
|
||||
ENV["DB"] ||= "mysql"
|
||||
|
||||
gem 'mysql2', '0.3.16' if ENV['DB'] == 'all' || ENV['DB'] == 'mysql'
|
||||
gem 'pg', '0.17.1' if ENV['DB'] == 'all' || ENV['DB'] == 'postgres'
|
||||
gem "mysql2", "0.3.18" if ENV["DB"] == "all" || ENV["DB"] == "mysql"
|
||||
gem "pg", "0.18.1" if ENV["DB"] == "all" || ENV["DB"] == "postgres"
|
||||
|
||||
gem 'activerecord-import', '0.3.1'
|
||||
gem 'foreigner', '1.6.1'
|
||||
gem "activerecord-import", "0.7.0"
|
||||
|
||||
# File uploading
|
||||
|
||||
gem 'carrierwave', '0.10.0'
|
||||
gem 'fog', '1.22.1'
|
||||
gem 'mini_magick', '3.7.0'
|
||||
gem 'remotipart', '1.2.1'
|
||||
gem "carrierwave", "0.10.0"
|
||||
gem "fog", "1.28.0"
|
||||
gem "mini_magick", "4.2.0"
|
||||
gem "remotipart", "1.2.1"
|
||||
|
||||
# GUID generation
|
||||
gem 'uuid', '2.3.7'
|
||||
gem "uuid", "2.3.7"
|
||||
|
||||
# Icons
|
||||
|
||||
gem "entypo-rails", "2.2.2"
|
||||
|
||||
# JavaScript
|
||||
|
||||
gem "backbone-on-rails", "1.1.2"
|
||||
gem "handlebars_assets", "0.20.1"
|
||||
gem "jquery-rails", "3.1.2"
|
||||
gem "js_image_paths", "0.0.2"
|
||||
gem "js-routes", "1.0.0"
|
||||
|
||||
source "https://rails-assets.org" do
|
||||
gem "rails-assets-jquery", "1.11.1" # Should be kept in sync with jquery-rails
|
||||
|
||||
gem "rails-assets-markdown-it", "4.2.0"
|
||||
gem "rails-assets-markdown-it-hashtag", "0.3.0"
|
||||
gem "rails-assets-markdown-it-diaspora-mention", "0.3.0"
|
||||
gem "rails-assets-markdown-it-sanitizer", "0.3.0"
|
||||
gem "rails-assets-markdown-it--markdown-it-for-inline", "0.1.0"
|
||||
gem "rails-assets-markdown-it-sub", "1.0.0"
|
||||
gem "rails-assets-markdown-it-sup", "1.0.0"
|
||||
|
||||
# jQuery plugins
|
||||
|
||||
gem "rails-assets-jeresig--jquery.hotkeys", "0.2.0"
|
||||
gem "rails-assets-jquery-idletimer", "1.0.1"
|
||||
gem "rails-assets-jquery-placeholder", "2.1.1"
|
||||
gem "rails-assets-jquery-textchange", "0.2.3"
|
||||
gem "rails-assets-perfect-scrollbar", "0.5.9"
|
||||
end
|
||||
|
||||
# Localization
|
||||
|
||||
gem 'http_accept_language', '1.0.2'
|
||||
gem 'i18n-inflector-rails', '1.0.7'
|
||||
gem 'rails-i18n', '0.7.4'
|
||||
gem "http_accept_language", "2.0.5"
|
||||
gem "i18n-inflector-rails", "1.0.7"
|
||||
gem "rails-i18n", "4.0.4"
|
||||
|
||||
# Mail
|
||||
|
||||
gem 'markerb', '1.0.2'
|
||||
gem 'messagebus_ruby_api', '1.0.3'
|
||||
gem "markerb", "1.0.2"
|
||||
gem "messagebus_ruby_api", "1.0.3"
|
||||
|
||||
# Parsing
|
||||
|
||||
gem 'nokogiri', '1.6.1'
|
||||
gem 'rails_autolink', '1.1.5'
|
||||
gem 'redcarpet', '3.2.3'
|
||||
gem 'roxml', '3.1.6'
|
||||
gem 'ruby-oembed', '0.8.9'
|
||||
gem 'opengraph_parser', '0.2.3'
|
||||
|
||||
|
||||
# Please remove when migrating to Rails 4
|
||||
gem 'strong_parameters', '0.2.3'
|
||||
|
||||
gem "nokogiri", "1.6.6.2"
|
||||
gem "redcarpet", "3.2.3"
|
||||
gem "twitter-text", "1.11.0"
|
||||
gem "roxml", "3.1.6"
|
||||
gem "ruby-oembed", "0.8.12"
|
||||
gem "open_graph_reader", "0.5.0"
|
||||
|
||||
# Services
|
||||
|
||||
gem 'omniauth', '1.2.1'
|
||||
gem 'omniauth-facebook', '1.6.0'
|
||||
gem 'omniauth-tumblr', '1.1'
|
||||
gem 'omniauth-twitter', '1.0.1'
|
||||
gem 'twitter', '4.8.1'
|
||||
gem 'omniauth-wordpress','0.2.1'
|
||||
gem "omniauth", "1.2.2"
|
||||
gem "omniauth-facebook", "1.6.0"
|
||||
gem "omniauth-tumblr", "1.1"
|
||||
gem "omniauth-twitter", "1.0.1"
|
||||
gem "twitter", "4.8.1"
|
||||
gem "omniauth-wordpress", "0.2.1"
|
||||
|
||||
# Serializers
|
||||
|
||||
gem "active_model_serializers", "0.9.3"
|
||||
|
||||
# XMPP chat dependencies
|
||||
gem "diaspora-vines", "~> 0.1.27"
|
||||
gem "rails-assets-diaspora_jsxc", "~> 0.1.1", source: "https://rails-assets.org"
|
||||
|
||||
# Tags
|
||||
|
||||
gem 'acts-as-taggable-on', '3.2.6'
|
||||
gem "acts-as-taggable-on", "3.5.0"
|
||||
|
||||
# URIs and HTTP
|
||||
|
||||
gem 'addressable', '2.3.6', :require => 'addressable/uri'
|
||||
gem 'faraday', '0.8.9'
|
||||
gem 'faraday_middleware', '0.9.0'
|
||||
gem 'typhoeus', '0.6.8'
|
||||
gem "addressable", "2.3.7", require: "addressable/uri"
|
||||
gem "faraday", "0.9.1"
|
||||
gem "faraday_middleware", "0.9.1"
|
||||
gem "faraday-cookie_jar", "0.0.6"
|
||||
gem "typhoeus", "0.7.1"
|
||||
|
||||
# Views
|
||||
|
||||
gem 'gon', '5.0.4'
|
||||
gem 'haml', '4.0.5'
|
||||
gem 'mobile-fu', '1.2.2'
|
||||
gem 'will_paginate', '3.0.5'
|
||||
gem 'rails-timeago', '2.4.0'
|
||||
gem "gon", "5.2.3"
|
||||
gem "haml", "4.0.6"
|
||||
gem "mobile-fu", "1.3.1"
|
||||
gem "will_paginate", "3.0.7"
|
||||
gem "rails-timeago", "2.11.0"
|
||||
|
||||
# Workarounds
|
||||
# https://github.com/rubyzip/rubyzip#important-note
|
||||
gem 'zip-zip'
|
||||
gem "zip-zip"
|
||||
|
||||
### GROUPS ####
|
||||
# Prevent occasions where minitest is not bundled in
|
||||
# packaged versions of ruby. See following issues/prs:
|
||||
# https://github.com/gitlabhq/gitlabhq/issues/3826
|
||||
# https://github.com/gitlabhq/gitlabhq/pull/3852
|
||||
# https://github.com/discourse/discourse/pull/238
|
||||
gem "minitest"
|
||||
|
||||
group :assets do
|
||||
# Windows and OSX have an execjs compatible runtime built-in, Linux users should
|
||||
# install Node.js or use "therubyracer".
|
||||
#
|
||||
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
|
||||
|
||||
# Icons
|
||||
gem 'entypo-rails', '2.2.1'
|
||||
|
||||
# CSS
|
||||
|
||||
gem 'bootstrap-sass', '2.2.2.0'
|
||||
gem 'compass-rails', '1.1.7'
|
||||
gem 'sass-rails', '3.2.6'
|
||||
|
||||
# Compression
|
||||
|
||||
gem 'uglifier', '2.5.0'
|
||||
|
||||
# JavaScript
|
||||
|
||||
gem 'backbone-on-rails', '1.1.1'
|
||||
gem 'handlebars_assets', '0.12.0'
|
||||
gem 'jquery-rails', '3.0.4'
|
||||
|
||||
# Windows and OSX have an execjs compatible runtime built-in, Linux users should
|
||||
# install Node.js or use 'therubyracer'.
|
||||
#
|
||||
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
|
||||
|
||||
# gem 'therubyracer', :platform => :ruby
|
||||
end
|
||||
|
||||
group :production do # we don't install these on travis to speed up test runs
|
||||
# gem "therubyracer", :platform => :ruby
|
||||
|
||||
group :production do # we don"t install these on travis to speed up test runs
|
||||
# Administration
|
||||
|
||||
gem 'rails_admin', '0.4.9'
|
||||
gem "rails_admin", "0.6.7"
|
||||
|
||||
# Analytics
|
||||
|
||||
gem 'rack-google-analytics', '0.14.0', :require => 'rack/google-analytics'
|
||||
gem 'rack-piwik', '0.2.2', :require => 'rack/piwik'
|
||||
gem "rack-google-analytics", "1.2.0"
|
||||
gem "rack-piwik", "0.3.0", require: "rack/piwik"
|
||||
|
||||
# Click-jacking protection
|
||||
|
||||
gem 'rack-protection', '1.2'
|
||||
gem "rack-protection", "1.5.3"
|
||||
|
||||
# Process management
|
||||
|
||||
gem 'foreman', '0.62'
|
||||
gem "foreman", "0.62"
|
||||
|
||||
# Redirects
|
||||
|
||||
gem 'rack-rewrite', '1.5.0', :require => false
|
||||
gem 'rack-ssl', '1.3.3', :require => 'rack/ssl'
|
||||
gem "rack-rewrite", "1.5.1", require: false
|
||||
gem "rack-ssl", "1.4.1", require: "rack/ssl"
|
||||
|
||||
# Third party asset hosting
|
||||
|
||||
gem 'asset_sync', '1.0.0', :require => false
|
||||
gem "asset_sync", "1.1.0", require: false
|
||||
end
|
||||
|
||||
group :development do
|
||||
# Automatic test runs
|
||||
gem 'guard-cucumber', '1.4.1'
|
||||
gem 'guard-rspec', '4.2.9'
|
||||
gem 'rb-fsevent', '0.9.4', :require => false
|
||||
gem 'rb-inotify', '0.9.4', :require => false
|
||||
gem "guard-cucumber", "1.5.4"
|
||||
gem "guard-jshintrb", "1.1.1"
|
||||
gem "guard-rspec", "4.5.0"
|
||||
gem "guard-rubocop", "1.2.0"
|
||||
gem "guard", "2.12.5", require: false
|
||||
gem "rb-fsevent", "0.9.4", require: false
|
||||
gem "rb-inotify", "0.9.5", require: false
|
||||
|
||||
# Linters
|
||||
gem "jshintrb", "0.3.0"
|
||||
gem "rubocop", "0.29.1"
|
||||
|
||||
# Preloading environment
|
||||
|
||||
gem 'guard-spork', '1.5.1'
|
||||
gem 'spork', '1.0.0rc4'
|
||||
gem "spring", "1.3.3"
|
||||
gem "spring-commands-rspec", "1.0.4"
|
||||
gem "spring-commands-cucumber", "1.0.1"
|
||||
|
||||
# Debugging
|
||||
gem "pry"
|
||||
gem "pry-debundle"
|
||||
gem "pry-byebug"
|
||||
end
|
||||
|
||||
group :test do
|
||||
# RSpec (unit tests, some integration tests)
|
||||
|
||||
gem 'fixture_builder', '0.3.6'
|
||||
gem 'fuubar', '1.3.3'
|
||||
gem 'rspec-instafail', '0.2.4', :require => false
|
||||
gem 'test_after_commit', '0.2.3'
|
||||
gem "fixture_builder", "0.3.6"
|
||||
gem "fuubar", "2.0.0"
|
||||
gem "rspec-instafail", "0.2.6", require: false
|
||||
gem "test_after_commit", "0.4.1"
|
||||
|
||||
# Cucumber (integration tests)
|
||||
|
||||
gem 'capybara', '2.2.1'
|
||||
gem 'database_cleaner', '1.3.0'
|
||||
gem 'selenium-webdriver', '2.42.0'
|
||||
gem "capybara", "2.4.4"
|
||||
gem "database_cleaner" , "1.4.1"
|
||||
gem "selenium-webdriver", "2.45.0"
|
||||
|
||||
# General helpers
|
||||
|
||||
gem 'factory_girl_rails', '4.4.1'
|
||||
gem 'timecop', '0.7.1'
|
||||
gem 'webmock', '1.18.0', :require => false
|
||||
gem "factory_girl_rails", "4.5.0"
|
||||
gem "timecop", "0.7.3"
|
||||
gem "webmock", "1.20.4", require: false
|
||||
gem "shoulda-matchers", "2.8.0", require: false
|
||||
end
|
||||
|
||||
|
||||
group :development, :test do
|
||||
# RSpec (unit tests, some integration tests)
|
||||
gem "rspec-rails", '2.14.2'
|
||||
gem "rspec-rails", "3.2.1"
|
||||
|
||||
# Cucumber (integration tests)
|
||||
gem 'cucumber-rails', '1.4.1', :require => false
|
||||
gem "cucumber-rails", "1.4.2", require: false
|
||||
|
||||
# Jasmine (client side application tests (JS))
|
||||
gem 'jasmine', '1.3.2'
|
||||
gem 'sinon-rails', '1.9.0'
|
||||
gem "jasmine", "2.2.0"
|
||||
gem "jasmine-jquery-rails", "2.0.3"
|
||||
gem "rails-assets-jasmine-ajax", "3.1.0", source: "https://rails-assets.org"
|
||||
gem "sinon-rails", "1.10.3"
|
||||
end
|
||||
|
|
|
|||
913
Gemfile.lock
65
Guardfile
|
|
@ -1,38 +1,45 @@
|
|||
# A sample Guardfile
|
||||
# More info at https://github.com/guard/guard#readme
|
||||
# also, http://asciicasts.com/episodes/264-guard
|
||||
guard 'rspec', :all_on_start => false, :all_after_pass => false do
|
||||
watch(%r{^spec/.+_spec\.rb$})
|
||||
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
||||
watch('spec/spec_helper.rb') { "spec" }
|
||||
guard :rspec, cmd: "bin/spring rspec", all_on_start: false, all_after_pass: false do
|
||||
watch(/^spec\/.+_spec\.rb$/)
|
||||
watch(/^lib\/(.+)\.rb$/) {|m| "spec/lib/#{m[1]}_spec.rb" }
|
||||
watch(/spec\/spec_helper.rb/) { "spec" }
|
||||
|
||||
# Rails example
|
||||
watch(%r{^spec/.+_spec\.rb$})
|
||||
watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
||||
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
||||
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
|
||||
watch(/^spec\/.+_spec\.rb$/)
|
||||
watch(/^app\/(.+)\.rb$/) {|m| "spec/#{m[1]}_spec.rb" }
|
||||
watch(/^lib\/(.+)\.rb$/) {|m| "spec/lib/#{m[1]}_spec.rb" }
|
||||
watch(%r{^app/controllers/(.+)_(controller)\.rb$}) {|m|
|
||||
["spec/routing/#{m[1]}_routing_spec.rb",
|
||||
"spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb",
|
||||
"spec/acceptance/#{m[1]}_spec.rb"]
|
||||
}
|
||||
watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
|
||||
watch('spec/spec_helper.rb') { "spec" }
|
||||
watch('config/routes.rb') { "spec/routing" }
|
||||
watch('app/controllers/application_controller.rb') { "spec/controllers" }
|
||||
watch("spec/spec_helper.rb") { "spec" }
|
||||
watch("config/routes.rb") { "spec/routing" }
|
||||
watch("app/controllers/application_controller.rb") { "spec/controllers" }
|
||||
|
||||
# Capybara request specs
|
||||
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
||||
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) {|m| "spec/requests/#{m[1]}_spec.rb" }
|
||||
end
|
||||
|
||||
guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAILS_ENV' => 'test' }, :all_on_start => false, :all_after_pass => false, :wait => 70 do
|
||||
watch('config/application.rb')
|
||||
watch('config/environment.rb')
|
||||
watch(%r{^config/environments/.+\.rb$})
|
||||
watch(%r{^config/initializers/.+\.rb$})
|
||||
watch('Gemfile')
|
||||
watch('Gemfile.lock')
|
||||
watch('spec/spec_helper.rb') { :rspec }
|
||||
watch('test/test_helper.rb') { :test_unit }
|
||||
watch(%r{features/support/}) { :cucumber }
|
||||
guard(:cucumber,
|
||||
command_prefix: "bin/spring",
|
||||
bundler: false,
|
||||
all_on_start: false,
|
||||
all_after_pass: false) do
|
||||
watch(/^features\/.+\.feature$/)
|
||||
watch(%r{^features/support/.+$}) { "features" }
|
||||
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) {|m|
|
||||
Dir[File.join("**/#{m[1]}.feature")][0] || "features"
|
||||
}
|
||||
end
|
||||
|
||||
guard 'cucumber', :all_on_start => false, :all_after_pass => false do
|
||||
watch(%r{^features/.+\.feature$})
|
||||
watch(%r{^features/support/.+$}) { 'features' }
|
||||
watch(%r{^features/step_definitions/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'features' }
|
||||
guard :rubocop, all_on_start: false, keep_failed: false do
|
||||
watch(/(?:app|config|db|lib|features|spec)\/.+\.rb$/)
|
||||
watch(/(config.ru|Gemfile|Guardfile|Rakefile)$/)
|
||||
end
|
||||
|
||||
guard :jshintrb do
|
||||
watch(/^app\/assets\/javascripts\/.+\.js$/)
|
||||
watch(/^lib\/assets\/javascripts\/.+\.js$/)
|
||||
watch(/^spec\/javascripts\/.+\.js$/)
|
||||
end
|
||||
|
|
|
|||
5
Procfile
|
|
@ -1,2 +1,3 @@
|
|||
web: bundle exec unicorn_rails -c config/unicorn.rb -p $PORT
|
||||
sidekiq: bundle exec sidekiq
|
||||
web: bin/bundle exec unicorn_rails -c config/unicorn.rb -p $PORT
|
||||
sidekiq: bin/bundle exec sidekiq
|
||||
xmpp: bin/bundle exec vines start
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# diaspora*
|
||||
### a privacy aware, distributed, open source social network
|
||||
### a privacy-aware, distributed, open source social network
|
||||
|
||||
**master:** [](http://travis-ci.org/diaspora/diaspora)
|
||||
**develop:** [](http://travis-ci.org/diaspora/diaspora) |
|
||||
|
|
|
|||
BIN
app/assets/images/branding/header-logo_hover.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 212 B |
0
app/assets/images/facebox/loading.gif
Executable file → Normal file
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 255 B |
BIN
app/assets/images/icons/create_participation.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
app/assets/images/icons/destroy_participation.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
0
app/assets/images/icons/menu.png
Executable file → Normal file
|
Before Width: | Height: | Size: 262 B After Width: | Height: | Size: 262 B |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
//= require_self
|
||||
//= require_tree ./helpers
|
||||
|
||||
|
|
@ -12,6 +14,8 @@
|
|||
//= require_tree ./collections
|
||||
//= require_tree ./views
|
||||
|
||||
//= require perfect-scrollbar
|
||||
|
||||
var app = {
|
||||
collections: {},
|
||||
models: {},
|
||||
|
|
@ -31,13 +35,11 @@ var app = {
|
|||
events: _.extend({}, Backbone.Events),
|
||||
|
||||
user: function(userAttrs) {
|
||||
if(userAttrs) { return this._user = new app.models.User(userAttrs) }
|
||||
return this._user || false
|
||||
},
|
||||
|
||||
baseImageUrl: function(baseUrl){
|
||||
if(baseUrl) { return this._baseImageUrl = baseUrl }
|
||||
return this._baseImageUrl || "assets/"
|
||||
if(userAttrs) {
|
||||
this._user = new app.models.User(userAttrs);
|
||||
return this._user;
|
||||
}
|
||||
return this._user || false;
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
|
|
@ -53,25 +55,25 @@ var app = {
|
|||
},
|
||||
|
||||
hasPreload : function(prop) {
|
||||
return !!(window.gon.preloads && window.gon.preloads[prop]) //returning boolean variable so that parsePreloads, which cleans up properly is used instead
|
||||
return !!(window.gon.preloads && window.gon.preloads[prop]); //returning boolean variable so that parsePreloads, which cleans up properly is used instead
|
||||
},
|
||||
|
||||
setPreload : function(prop, val) {
|
||||
window.gon.preloads = window.gon.preloads || {}
|
||||
window.gon.preloads[prop] = val
|
||||
window.gon.preloads = window.gon.preloads || {};
|
||||
window.gon.preloads[prop] = val;
|
||||
},
|
||||
|
||||
parsePreload : function(prop) {
|
||||
if(!app.hasPreload(prop)) { return }
|
||||
|
||||
var preload = window.gon.preloads[prop]
|
||||
delete window.gon.preloads[prop] //prevent dirty state across navigates
|
||||
var preload = window.gon.preloads[prop];
|
||||
delete window.gon.preloads[prop]; //prevent dirty state across navigates
|
||||
|
||||
return(preload)
|
||||
return(preload);
|
||||
},
|
||||
|
||||
setupDummyPreloads: function() {
|
||||
if (window.gon == undefined) {
|
||||
if (window.gon === undefined) {
|
||||
window.gon = {preloads:{}};
|
||||
}
|
||||
},
|
||||
|
|
@ -89,8 +91,8 @@ var app = {
|
|||
},
|
||||
|
||||
setupFacebox: function() {
|
||||
$.facebox.settings.closeImage = app.baseImageUrl()+'facebox/closelabel.png';
|
||||
$.facebox.settings.loadingImage = app.baseImageUrl()+'facebox/loading.gif';
|
||||
$.facebox.settings.closeImage = ImagePaths.get('facebox/closelabel.png');
|
||||
$.facebox.settings.loadingImage = ImagePaths.get('facebox/loading.gif');
|
||||
$.facebox.settings.opacity = 0.75;
|
||||
},
|
||||
|
||||
|
|
@ -102,14 +104,13 @@ var app = {
|
|||
evt.preventDefault();
|
||||
var link = $(this);
|
||||
|
||||
$(".stream_title").text(link.text())
|
||||
app.router.navigate(link.attr("href").substring(1) ,true)
|
||||
$(".stream_title").text(link.text());
|
||||
app.router.navigate(link.attr("href").substring(1) ,true);
|
||||
});
|
||||
},
|
||||
|
||||
setupGlobalViews: function() {
|
||||
app.hovercard = new app.views.Hovercard();
|
||||
app.aspectMembershipsBlueprint = new app.views.AspectMembershipBlueprint();
|
||||
$('.aspect_membership_dropdown').each(function(){
|
||||
new app.views.AspectMembership({el: this});
|
||||
});
|
||||
|
|
@ -119,7 +120,7 @@ var app = {
|
|||
/* mixpanel wrapper function */
|
||||
instrument : function(type, name, object, callback) {
|
||||
if(!window.mixpanel) { return }
|
||||
window.mixpanel[type](name, object, callback)
|
||||
window.mixpanel[type](name, object, callback);
|
||||
},
|
||||
|
||||
setupDisabledLinks: function() {
|
||||
|
|
@ -132,3 +133,4 @@ var app = {
|
|||
$(function() {
|
||||
app.initialize();
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.collections.AspectMemberships = Backbone.Collection.extend({
|
||||
model: app.models.AspectMembership
|
||||
});
|
||||
// @license-end
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.collections.Aspects = Backbone.Collection.extend({
|
||||
model: app.models.Aspect,
|
||||
|
||||
|
|
@ -23,4 +25,5 @@ app.collections.Aspects = Backbone.Collection.extend({
|
|||
var separator = Diaspora.I18n.t("comma") + ' ';
|
||||
return this.selectedAspects('name').join(separator).replace(/,\s([^,]+)$/, ' ' + Diaspora.I18n.t("and") + ' $1') || Diaspora.I18n.t("my_aspects");
|
||||
}
|
||||
})
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.collections.Comments = Backbone.Collection.extend({
|
||||
model: app.models.Comment,
|
||||
url: function() { return _.result(this.post, 'url') + '/comments'; },
|
||||
|
|
@ -14,11 +16,12 @@ app.collections.Comments = Backbone.Collection.extend({
|
|||
var deferred = comment.save({}, {
|
||||
url: '/posts/'+this.post.id+'/comments',
|
||||
success: function() {
|
||||
comment.set({author: app.currentUser.toJSON(), parent: self.post })
|
||||
self.add(comment)
|
||||
comment.set({author: app.currentUser.toJSON(), parent: self.post });
|
||||
self.add(comment);
|
||||
}
|
||||
});
|
||||
|
||||
return deferred;
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
21
app/assets/javascripts/app/collections/contacts.js
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.collections.Contacts = Backbone.Collection.extend({
|
||||
model: app.models.Contact,
|
||||
|
||||
comparator : function(con1, con2) {
|
||||
if( !con1.person || !con2.person ) return 1;
|
||||
|
||||
if(app.aspect) {
|
||||
var inAspect1 = con1.inAspect(app.aspect.get('id'));
|
||||
var inAspect2 = con2.inAspect(app.aspect.get('id'));
|
||||
if( inAspect1 && !inAspect2 ) return -1;
|
||||
if( !inAspect1 && inAspect2 ) return 1;
|
||||
}
|
||||
|
||||
var n1 = con1.person.get('name');
|
||||
var n2 = con2.person.get('name');
|
||||
return n1.localeCompare(n2);
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
@ -1,7 +1,10 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.collections.Likes = Backbone.Collection.extend({
|
||||
model: app.models.Like,
|
||||
|
||||
initialize : function(models, options) {
|
||||
this.url = "/posts/" + options.post.id + "/likes" //not delegating to post.url() because when it is in a stream collection it delegates to that url
|
||||
this.url = "/posts/" + options.post.id + "/likes"; //not delegating to post.url() because when it is in a stream collection it delegates to that url
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.collections.Photos = Backbone.Collection.extend({
|
||||
url : "/photos",
|
||||
|
||||
model: function(attrs, options) {
|
||||
var modelClass = app.models.Photo
|
||||
var modelClass = app.models.Photo;
|
||||
return new modelClass(attrs, options);
|
||||
},
|
||||
|
||||
|
|
@ -10,3 +12,4 @@ app.collections.Photos = Backbone.Collection.extend({
|
|||
return resp.photos;
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.collections.Posts = Backbone.Collection.extend({
|
||||
model: app.models.Post,
|
||||
url : "/posts"
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.collections.Reshares = Backbone.Collection.extend({
|
||||
model: app.models.Reshare,
|
||||
url : "/reshares"
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.collections.TagFollowings = Backbone.Collection.extend({
|
||||
|
||||
model: app.models.TagFollowing,
|
||||
|
|
@ -17,3 +19,5 @@ app.collections.TagFollowings = Backbone.Collection.extend({
|
|||
}
|
||||
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
(function(){
|
||||
app.helpers.dateFormatter = {
|
||||
parse:function (dateString) {
|
||||
|
|
@ -12,5 +14,6 @@
|
|||
|
||||
return timestamp || 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
})();
|
||||
// @license-end
|
||||
|
|
|
|||
95
app/assets/javascripts/app/helpers/direction_detector.js
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
(function() {
|
||||
app.helpers.txtDirection = {
|
||||
setCssFor: function(str, on_element) {
|
||||
if( this.isRTL(str) ) {
|
||||
$(on_element).css('direction', 'rtl');
|
||||
} else {
|
||||
$(on_element).css('direction', 'ltr');
|
||||
}
|
||||
},
|
||||
|
||||
classFor: function(str) {
|
||||
if( this.isRTL(str) ) return 'rtl';
|
||||
return 'ltr';
|
||||
},
|
||||
|
||||
isRTL: function(str) {
|
||||
if(typeof str !== "string" || str.length < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var charCode = this._fixedCharCodeAt(str, 0);
|
||||
if(charCode >= 1536 && charCode <= 1791) // Sarabic, Persian, ...
|
||||
return true;
|
||||
|
||||
else if(charCode >= 65136 && charCode <= 65279) // Arabic present 1
|
||||
return true;
|
||||
|
||||
else if(charCode >= 64336 && charCode <= 65023) // Arabic present 2
|
||||
return true;
|
||||
|
||||
else if(charCode>=1424 && charCode<=1535) // Hebrew
|
||||
return true;
|
||||
|
||||
else if(charCode>=64256 && charCode<=64335) // Hebrew present
|
||||
return true;
|
||||
|
||||
else if(charCode>=68096 && charCode<=68184) // Kharoshthi
|
||||
return true;
|
||||
|
||||
else if(charCode>=67840 && charCode<=67871) // Phoenician
|
||||
return true;
|
||||
|
||||
else if(charCode>=1792 && charCode<=1871) // Syriac
|
||||
return true;
|
||||
|
||||
else if(charCode>=1920 && charCode<=1983) // Thaana
|
||||
return true;
|
||||
|
||||
else if(charCode>=1984 && charCode<=2047) // NKo
|
||||
return true;
|
||||
|
||||
else if(charCode>=11568 && charCode<=11647) // Tifinagh
|
||||
return true;
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
// source: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt
|
||||
_fixedCharCodeAt: function(str, idx) {
|
||||
str += '';
|
||||
var code,
|
||||
end = str.length;
|
||||
|
||||
var surrogatePairs = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
||||
while ((surrogatePairs.exec(str)) != null) {
|
||||
var li = surrogatePairs.lastIndex;
|
||||
if (li - 2 < idx) {
|
||||
idx++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (idx >= end || idx < 0) {
|
||||
return NaN;
|
||||
}
|
||||
|
||||
code = str.charCodeAt(idx);
|
||||
|
||||
var hi, low;
|
||||
if (0xD800 <= code && code <= 0xDBFF) {
|
||||
hi = code;
|
||||
low = str.charCodeAt(idx+1);
|
||||
// Go one further, since one of the "characters" is part of a surrogate pair
|
||||
return ((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
};
|
||||
})();
|
||||
// @license-end
|
||||
|
||||
|
|
@ -1,26 +1,67 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
Handlebars.registerHelper('t', function(scope, values) {
|
||||
return Diaspora.I18n.t(scope, values.hash)
|
||||
return Diaspora.I18n.t(scope, values.hash);
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('txtDirClass', function(str) {
|
||||
return app.helpers.txtDirection.classFor(str);
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('imageUrl', function(path){
|
||||
return app.baseImageUrl() + path;
|
||||
return ImagePaths.get(path);
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('linkToPerson', function(context, block) {
|
||||
Handlebars.registerHelper('urlTo', function(path_helper, id, data){
|
||||
if( !data ) {
|
||||
// only one argument given to helper, mangle parameters
|
||||
data = id;
|
||||
return Routes[path_helper+'_path'](data.hash);
|
||||
}
|
||||
return Routes[path_helper+'_path'](id, data.hash);
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('linkToAuthor', function(context, block) {
|
||||
if( !context ) context = this;
|
||||
var html = "<a href=\"/people/" + context.guid + "\" class=\"author-name ";
|
||||
html += Handlebars.helpers.hovercardable(context);
|
||||
html += "\">";
|
||||
html += block.fn(context);
|
||||
html += "</a>";
|
||||
|
||||
return html
|
||||
return html;
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('linkToPerson', function(context, block) {
|
||||
if( !context ) context = this;
|
||||
var html = "<a href=\"/people/" + context.guid + "\" class=\"name\">";
|
||||
html += block.fn(context);
|
||||
html += "</a>";
|
||||
|
||||
return html;
|
||||
});
|
||||
|
||||
// relationship indicator for profile page
|
||||
Handlebars.registerHelper('sharingMessage', function(person) {
|
||||
var i18n_scope = 'people.helper.is_not_sharing';
|
||||
var icon = "circle";
|
||||
if( person.is_sharing ) {
|
||||
i18n_scope = 'people.helper.is_sharing';
|
||||
icon = "entypo check";
|
||||
}
|
||||
|
||||
var title = Diaspora.I18n.t(i18n_scope, {name: person.name});
|
||||
var html = '<span class="sharing_message_container" title="'+title+'" data-placement="bottom">'+
|
||||
' <i id="sharing_message" class="'+icon+'"></i>'+
|
||||
'</span>';
|
||||
return html;
|
||||
});
|
||||
|
||||
|
||||
// allow hovercards for users that are not the current user.
|
||||
// returns the html class name used to trigger hovercards.
|
||||
Handlebars.registerHelper('hovercardable', function(person) {
|
||||
if( app.currentUser.get('guid') != person.guid ) {
|
||||
if( app.currentUser.get('guid') !== person.guid ) {
|
||||
return 'hovercardable';
|
||||
}
|
||||
return '';
|
||||
|
|
@ -29,18 +70,65 @@ Handlebars.registerHelper('hovercardable', function(person) {
|
|||
Handlebars.registerHelper('personImage', function(person, size, imageClass) {
|
||||
/* we return here if person.avatar is blank, because this happens when a
|
||||
* user is unauthenticated. we don't know why this happens... */
|
||||
if( _.isUndefined(person.avatar) ) { return }
|
||||
if( !person.avatar &&
|
||||
!(person.profile && person.profile.avatar) ) return;
|
||||
var avatar = person.avatar || person.profile.avatar;
|
||||
|
||||
var name = ( person.name ) ? person.name : 'avatar';
|
||||
size = ( !_.isString(size) ) ? "small" : size;
|
||||
imageClass = ( !_.isString(imageClass) ) ? size : imageClass;
|
||||
|
||||
return _.template('<img src="<%= src %>" class="avatar <%= img_class %>" title="<%= title %>" />', {
|
||||
'src': person.avatar[size],
|
||||
return _.template('<img src="<%= src %>" class="avatar <%= img_class %>" title="<%= title %>" alt="<%= title %>" />')({
|
||||
'src': avatar[size],
|
||||
'img_class': imageClass,
|
||||
'title': _.escape(person.name)
|
||||
'title': _.escape(name)
|
||||
});
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('localTime', function(timestamp) {
|
||||
return new Date(timestamp).toLocaleString();
|
||||
});
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('fmtTags', function(tags) {
|
||||
var links = _.map(tags, function(tag) {
|
||||
return '<a class="tag" href="' + Routes.tag_path(tag) + '">' +
|
||||
' #' + tag +
|
||||
'</a>';
|
||||
}).join(' ');
|
||||
return new Handlebars.SafeString(links);
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('fmtText', function(text) {
|
||||
return new Handlebars.SafeString(app.helpers.textFormatter(text));
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('isCurrentPage', function(path_helper, id, options){
|
||||
var currentPage = "/"+Backbone.history.fragment;
|
||||
if (currentPage === Handlebars.helpers.urlTo(path_helper, id, options.data)) {
|
||||
return options.fn(this);
|
||||
} else {
|
||||
return options.inverse(this);
|
||||
}
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('isCurrentProfilePage', function(id, diaspora_handle, options){
|
||||
var username = diaspora_handle.split("@")[0];
|
||||
return Handlebars.helpers.isCurrentPage('person', id, options) ||
|
||||
Handlebars.helpers.isCurrentPage('user_profile', username, options);
|
||||
});
|
||||
|
||||
Handlebars.registerHelper('aspectMembershipIndicator', function(contact,in_aspect) {
|
||||
if(!app.aspect || !app.aspect.get('id')) return '<div class="aspect_membership_dropdown placeholder"></div>';
|
||||
|
||||
var html = '<i class="entypo ';
|
||||
if( in_aspect === 'in_aspect' ) {
|
||||
html += 'circled-cross contact_remove-from-aspect" ';
|
||||
html += 'title="' + Diaspora.I18n.t('contacts.remove_contact') + '" ';
|
||||
} else {
|
||||
html += 'circled-plus contact_add-to-aspect" ';
|
||||
html += 'title="' + Diaspora.I18n.t('contacts.add_contact') + '" ';
|
||||
}
|
||||
html += '></i>';
|
||||
return html;
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
/* we need to wrap this in a document ready to ensure JST is accessible */
|
||||
$(function(){
|
||||
Handlebars.registerPartial('status-message', JST['status-message_tpl'])
|
||||
Handlebars.registerPartial('status-message', HandlebarsTemplates['status-message_tpl']);
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
(function(){
|
||||
app.helpers.oEmbed = {
|
||||
html : function (o_embed_cache) {
|
||||
if (!o_embed_cache) { return "" }
|
||||
|
||||
var data = o_embed_cache.data;
|
||||
if (data.type == "photo") {
|
||||
return '<img src="' + data.url + '" width="' + data.width + '" height="' + data.height + '" />'
|
||||
if (data.type === "photo") {
|
||||
return '<img src="' + data.url + '" width="' + data.width + '" height="' + data.height + '" />';
|
||||
} else {
|
||||
return data.html || ""
|
||||
return data.html || "";
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
};
|
||||
})();
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
(function(){
|
||||
app.helpers.openGraph = {
|
||||
html : function (open_graph_cache) {
|
||||
if (!open_graph_cache) { return "" }
|
||||
return '<img src="' + open_graph_cache.image + '" />'
|
||||
}
|
||||
}
|
||||
if (!open_graph_cache) { return ""; }
|
||||
return '<img src="' + open_graph_cache.image + '" />';
|
||||
},
|
||||
};
|
||||
})();
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,144 +1,66 @@
|
|||
|
||||
// cache url regex globally, for direct acces when testing
|
||||
$(function() {
|
||||
Diaspora.url_regex = /(^|\s)\b((?:(?:https?|ftp):(?:\/{1,3})|www\.)(?:[^"<>\)\s]|\(([^\s()<>]+|(\([^\s()<>]+\)))\))+)(?=\s|$)/gi;
|
||||
});
|
||||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
(function(){
|
||||
//make it so I take text and mentions rather than the modelapp.helpers.textFormatter(
|
||||
var textFormatter = function textFormatter(text, model) {
|
||||
var mentions = model.get("mentioned_people");
|
||||
app.helpers.textFormatter = function(text, mentions) {
|
||||
mentions = mentions ? mentions : [];
|
||||
|
||||
return textFormatter.mentionify(
|
||||
textFormatter.hashtagify(
|
||||
textFormatter.markdownify(text)
|
||||
), mentions
|
||||
)
|
||||
};
|
||||
var md = window.markdownit({
|
||||
breaks: true,
|
||||
html: true,
|
||||
linkify: true,
|
||||
typographer: true
|
||||
});
|
||||
|
||||
textFormatter.markdownify = function markdownify(text){
|
||||
var converter = Markdown.getSanitizingConverter();
|
||||
var inlinePlugin = window.markdownitForInline;
|
||||
md.use(inlinePlugin, "utf8_symbols", "text", function (tokens, idx) {
|
||||
tokens[idx].content = tokens[idx].content.replace(/<->/g, "↔")
|
||||
.replace(/<-/g, "←")
|
||||
.replace(/->/g, "→")
|
||||
.replace(/<3/g, "♥");
|
||||
});
|
||||
|
||||
// punycode non-ascii chars in urls
|
||||
converter.hooks.chain("preConversion", function(text) {
|
||||
|
||||
// add < > around plain urls, effectively making them "autolinks"
|
||||
text = text.replace(Diaspora.url_regex, function() {
|
||||
var url = arguments[2];
|
||||
if( url.match(/^[^\w]/) ) return url; // evil witchcraft, noop
|
||||
return arguments[1]+"<"+url+">";
|
||||
});
|
||||
|
||||
// process links
|
||||
// regex copied from: https://code.google.com/p/pagedown/source/browse/Markdown.Converter.js#1198 (and slightly expanded)
|
||||
var linkRegex = /(\[.*\]:\s)?(<|\()((?:(https?|ftp):\/\/[^\/'">\s]|www)[^'">\s]+?)([>\)]{1,2})/gi;
|
||||
text = text.replace(linkRegex, function() {
|
||||
var unicodeUrl = arguments[3];
|
||||
var urlSuffix = arguments[5];
|
||||
|
||||
unicodeUrl = ( unicodeUrl.match(/^www/) ) ? ('http://' + unicodeUrl) : unicodeUrl;
|
||||
|
||||
// handle parentheses, especially in case the link ends with ')'
|
||||
if( urlSuffix.indexOf(')') != -1 && urlSuffix.indexOf('>') != -1 ) {
|
||||
unicodeUrl += ')';
|
||||
urlSuffix = '>';
|
||||
}
|
||||
|
||||
// url*DE*code as much as possible
|
||||
try {
|
||||
while( unicodeUrl.indexOf("%") !== -1 && unicodeUrl != decodeURI(unicodeUrl) ) {
|
||||
unicodeUrl = decodeURI(unicodeUrl);
|
||||
}
|
||||
}
|
||||
catch(e){}
|
||||
|
||||
// markdown doesn't like '(' or ')' anywhere, except where it wants
|
||||
var workingUrl = unicodeUrl.replace(/\(/, "%28").replace(/\)/, "%29");
|
||||
|
||||
var addr = parse_url(unicodeUrl);
|
||||
if( !addr.host ) addr.host = ""; // must not be 'undefined'
|
||||
|
||||
var asciiUrl = // rebuild the url
|
||||
(!addr.scheme ? '' : addr.scheme +
|
||||
( (addr.scheme.toLowerCase()=="mailto") ? ':' : '://')) +
|
||||
(!addr.user ? '' : addr.user +
|
||||
(!addr.pass ? '' : ':'+addr.pass) + '@') +
|
||||
punycode.toASCII(addr.host) +
|
||||
(!addr.port ? '' : ':' + addr.port) +
|
||||
(!addr.path ? '' : encodeURI(addr.path) ) +
|
||||
(!addr.query ? '' : '?' + encodeURI(addr.query) ) +
|
||||
(!addr.fragment ? '' : '#' + encodeURI(addr.fragment) );
|
||||
if( !arguments[1] || arguments[1] == "") { // inline link
|
||||
if(arguments[2] == "<") return "["+workingUrl+"]("+asciiUrl+")"; // without link text
|
||||
else return arguments[2]+asciiUrl+urlSuffix; // with link text
|
||||
} else { // reference style link
|
||||
return arguments[1]+asciiUrl;
|
||||
md.use(inlinePlugin, "link_new_window_and_missing_http", "link_open", function (tokens, idx) {
|
||||
tokens[idx].attrs.forEach(function(attribute, index, array) {
|
||||
if( attribute[0] === "href" ) {
|
||||
array[index][1] = attribute[1].replace(/^www\./, "http://www.");
|
||||
}
|
||||
});
|
||||
|
||||
return text;
|
||||
tokens[idx].attrPush([ "target", "_blank" ]);
|
||||
});
|
||||
|
||||
// make nice little utf-8 symbols
|
||||
converter.hooks.chain("preConversion", function(text) {
|
||||
var input_strings = [
|
||||
"<->", "->", "<-",
|
||||
"(c)", "(r)", "(tm)",
|
||||
"<3"
|
||||
];
|
||||
var output_symbols = [
|
||||
"↔", "→", "←",
|
||||
"©", "®", "™",
|
||||
"♥"
|
||||
];
|
||||
// quote function from: http://stackoverflow.com/a/494122
|
||||
var quote = function(str) {
|
||||
return str.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
|
||||
};
|
||||
|
||||
_.each(input_strings, function(str, idx) {
|
||||
var r = new RegExp(quote(str), "gi");
|
||||
text = text.replace(r, output_symbols[idx]);
|
||||
});
|
||||
return text;
|
||||
var hashtagPlugin = window.markdownitHashtag;
|
||||
md.use(hashtagPlugin, {
|
||||
// compare tag_text_regexp in app/models/acts_as_taggable_on-tag.rb
|
||||
hashtagRegExp: "[" + PosixBracketExpressions.alnum + "_\\-]+|<3",
|
||||
// compare tag_strings in lib/diaspora/taggabe.rb
|
||||
preceding: "^|\\s"
|
||||
});
|
||||
|
||||
converter.hooks.chain("postConversion", function (text) {
|
||||
return text.replace(/(\"(?:(?:http|https):\/\/)?[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(?:\/\S*)?\")(\>)/g, '$1 target="_blank">')
|
||||
var mentionPlugin = window.markdownitDiasporaMention;
|
||||
md.use(mentionPlugin, {
|
||||
mentions: mentions,
|
||||
allowHovercards: true,
|
||||
currentUserId: app.currentUser.get("guid")
|
||||
});
|
||||
|
||||
return converter.makeHtml(text)
|
||||
var subPlugin = window.markdownitSub;
|
||||
md.use(subPlugin);
|
||||
var supPlugin = window.markdownitSup;
|
||||
md.use(supPlugin);
|
||||
var sanitizerPlugin = window.markdownitSanitizer;
|
||||
md.use(sanitizerPlugin);
|
||||
|
||||
// xmpp: should behave like mailto:
|
||||
md.linkify.add("xmpp:","mailto:");
|
||||
// mumble:// should behave like http://:
|
||||
md.linkify.add("mumble:","http:");
|
||||
md.linkify.set({ fuzzyLink: false });
|
||||
|
||||
// Bootstrap table markup
|
||||
md.renderer.rules.table_open = function () { return "<table class=\"table table-striped\">\n"; };
|
||||
|
||||
return md.render(text);
|
||||
};
|
||||
|
||||
textFormatter.hashtagify = function hashtagify(text){
|
||||
var utf8WordCharcters =/(<a[^>]*>.*?<\/a>)|(\s|^|>)#([\u0080-\uFFFF|\w|-]+|<3)/g;
|
||||
|
||||
return text.replace(utf8WordCharcters, function(result, linkTag, preceeder, tagText) {
|
||||
if(linkTag)
|
||||
return linkTag;
|
||||
else
|
||||
return preceeder + "<a href='/tags/" + tagText.toLowerCase() +
|
||||
"' class='tag'>#" + tagText + "</a>";
|
||||
});
|
||||
};
|
||||
|
||||
textFormatter.mentionify = function mentionify(text, mentions) {
|
||||
var mentionRegex = /@\{([^;]+); ([^\}]+)\}/g
|
||||
return text.replace(mentionRegex, function(mentionText, fullName, diasporaId) {
|
||||
var person = _.find(mentions, function(person){
|
||||
return (diasporaId == person.diaspora_id || person.handle) //jquery.mentionsInput gives us person.handle
|
||||
})
|
||||
if(person) {
|
||||
var url = person.url || "/people/" + person.guid //jquery.mentionsInput gives us person.url
|
||||
, personText = "<a href='" + url + "' class='mention'>" + fullName + "</a>"
|
||||
} else {
|
||||
personText = fullName;
|
||||
}
|
||||
|
||||
return personText
|
||||
})
|
||||
}
|
||||
|
||||
app.helpers.textFormatter = textFormatter;
|
||||
})();
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
9
app/assets/javascripts/app/helpers/timeago.js
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
(function(){
|
||||
app.helpers.timeago = function(el) {
|
||||
el.find('time.timeago').each(function(i,e) {
|
||||
$(e).attr('title', new Date($(e).attr('datetime')).toLocaleString());
|
||||
}).timeago().tooltip();
|
||||
};
|
||||
})();
|
||||
// @license-end
|
||||
14
app/assets/javascripts/app/helpers/truncate.js
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
(function() {
|
||||
app.helpers.truncate = function(passedString, length) {
|
||||
if (passedString === null || passedString === undefined) {
|
||||
return passedString;
|
||||
}
|
||||
|
||||
if (passedString.length > length) {
|
||||
var lastBlank = passedString.lastIndexOf(' ', length);
|
||||
var trimstring = passedString.substring(0, Math.min(length, lastBlank));
|
||||
return new Handlebars.SafeString(trimstring + " ...");
|
||||
}
|
||||
return new Handlebars.SafeString(passedString);
|
||||
};
|
||||
})();
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
// Mixin to provide date formatting and "createdAt" method
|
||||
// other attributes can be accessed by calling this.timeOf("timestamp-field")
|
||||
|
|
@ -14,3 +15,5 @@ app.models.formatDateMixin = {
|
|||
}
|
||||
|
||||
};
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.Aspect = Backbone.Model.extend({
|
||||
toggleSelected: function(){
|
||||
this.set({'selected' : !this.get('selected')}, {async: false});
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
/**
|
||||
* this model represents the assignment of an aspect to a person.
|
||||
* (only valid for the context of the current user)
|
||||
*/
|
||||
app.models.AspectMembership = Backbone.Model.extend({
|
||||
urlRoot: "/aspect_memberships"
|
||||
});
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.Block = Backbone.Model.extend({
|
||||
urlRoot : "/blocks"
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.Comment = Backbone.Model.extend({
|
||||
urlRoot: "/comments"
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
13
app/assets/javascripts/app/models/contact.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.Contact = Backbone.Model.extend({
|
||||
initialize : function() {
|
||||
this.aspect_memberships = new app.collections.AspectMemberships(this.get('aspect_memberships'));
|
||||
if( this.get('person') ) this.person = new app.models.Person(this.get('person'));
|
||||
},
|
||||
|
||||
inAspect : function(id) {
|
||||
return this.aspect_memberships.any(function(membership){ return membership.get('aspect').id === id; });
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
@ -1 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.Like = Backbone.Model.extend({ });
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
53
app/assets/javascripts/app/models/person.js
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.Person = Backbone.Model.extend({
|
||||
url: function() {
|
||||
return Routes.person_path(this.get('guid'));
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
if( this.get('profile') )
|
||||
this.profile = new app.models.Profile(this.get('profile'));
|
||||
},
|
||||
|
||||
isSharing: function() {
|
||||
var rel = this.get('relationship');
|
||||
return (rel === 'mutual' || rel === 'sharing');
|
||||
},
|
||||
|
||||
isReceiving: function() {
|
||||
var rel = this.get('relationship');
|
||||
return (rel === 'mutual' || rel === 'receiving');
|
||||
},
|
||||
|
||||
isMutual: function() {
|
||||
return (this.get('relationship') === 'mutual');
|
||||
},
|
||||
|
||||
isBlocked: function() {
|
||||
return (this.get('relationship') === 'blocked');
|
||||
},
|
||||
|
||||
block: function() {
|
||||
var self = this;
|
||||
var block = new app.models.Block({block: {person_id: this.id}});
|
||||
|
||||
// return the jqXHR with Promise interface
|
||||
return block.save()
|
||||
.done(function() { app.events.trigger('person:block:'+self.id); });
|
||||
},
|
||||
|
||||
unblock: function() {
|
||||
var self = this;
|
||||
if( !this.get('block') ) {
|
||||
var def = $.Deferred();
|
||||
return def.reject();
|
||||
}
|
||||
|
||||
var block = new app.models.Block({id: this.get('block').id});
|
||||
return block.destroy()
|
||||
.done(function() { app.events.trigger('person:unblock:'+self.id); });
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.Photo = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin, {
|
||||
urlRoot : "/photos",
|
||||
|
||||
initialize : function() {},
|
||||
|
||||
}));
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.PollParticipation = Backbone.Model.extend({
|
||||
urlRoot: function(){
|
||||
return '/posts/' + this.get('post_id') + "/poll_participations";
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,20 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin, {
|
||||
urlRoot : "/posts",
|
||||
|
||||
initialize : function() {
|
||||
this.interactions = new app.models.Post.Interactions(_.extend({post : this}, this.get("interactions")))
|
||||
this.delegateToInteractions()
|
||||
this.interactions = new app.models.Post.Interactions(_.extend({post : this}, this.get("interactions")));
|
||||
this.delegateToInteractions();
|
||||
},
|
||||
|
||||
delegateToInteractions : function(){
|
||||
this.comments = this.interactions.comments
|
||||
this.likes = this.interactions.likes
|
||||
this.comments = this.interactions.comments;
|
||||
this.likes = this.interactions.likes;
|
||||
|
||||
this.comment = function(){
|
||||
this.interactions.comment.apply(this.interactions, arguments)
|
||||
}
|
||||
this.interactions.comment.apply(this.interactions, arguments);
|
||||
};
|
||||
},
|
||||
|
||||
interactedAt : function() {
|
||||
|
|
@ -20,11 +22,12 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin,
|
|||
},
|
||||
|
||||
reshare : function(){
|
||||
return this._reshare = this._reshare || new app.models.Reshare({root_guid : this.get("guid")});
|
||||
this._reshare = this._reshare || new app.models.Reshare({root_guid : this.get("guid")});
|
||||
return this._reshare;
|
||||
},
|
||||
|
||||
reshareAuthor : function(){
|
||||
return this.get("author")
|
||||
return this.get("author");
|
||||
},
|
||||
|
||||
blockAuthor: function() {
|
||||
|
|
@ -36,7 +39,7 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin,
|
|||
},
|
||||
|
||||
toggleFavorite : function(options){
|
||||
this.set({favorite : !this.get("favorite")})
|
||||
this.set({favorite : !this.get("favorite")});
|
||||
|
||||
/* guard against attempting to save a model that a user doesn't own */
|
||||
if(options.save){ this.save() }
|
||||
|
|
@ -44,27 +47,29 @@ app.models.Post = Backbone.Model.extend(_.extend({}, app.models.formatDateMixin,
|
|||
|
||||
headline : function() {
|
||||
var headline = this.get("text").trim()
|
||||
, newlineIdx = headline.indexOf("\n")
|
||||
return (newlineIdx > 0 ) ? headline.substr(0, newlineIdx) : headline
|
||||
, newlineIdx = headline.indexOf("\n");
|
||||
return (newlineIdx > 0 ) ? headline.substr(0, newlineIdx) : headline;
|
||||
},
|
||||
|
||||
body : function(){
|
||||
var body = this.get("text").trim()
|
||||
, newlineIdx = body.indexOf("\n")
|
||||
return (newlineIdx > 0 ) ? body.substr(newlineIdx+1, body.length) : ""
|
||||
, newlineIdx = body.indexOf("\n");
|
||||
return (newlineIdx > 0 ) ? body.substr(newlineIdx+1, body.length) : "";
|
||||
},
|
||||
|
||||
//returns a promise
|
||||
preloadOrFetch : function(){
|
||||
var action = app.hasPreload("post") ? this.set(app.parsePreload("post")) : this.fetch()
|
||||
return $.when(action)
|
||||
var action = app.hasPreload("post") ? this.set(app.parsePreload("post")) : this.fetch();
|
||||
return $.when(action);
|
||||
},
|
||||
|
||||
hasPhotos : function(){
|
||||
return this.get("photos") && this.get("photos").length > 0
|
||||
return this.get("photos") && this.get("photos").length > 0;
|
||||
},
|
||||
|
||||
hasText : function(){
|
||||
return $.trim(this.get("text")) !== ""
|
||||
return $.trim(this.get("text")) !== "";
|
||||
}
|
||||
}));
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,136 +1,139 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
//require ../post
|
||||
|
||||
app.models.Post.Interactions = Backbone.Model.extend({
|
||||
url : function(){
|
||||
return this.post.url() + "/interactions"
|
||||
return this.post.url() + "/interactions";
|
||||
},
|
||||
|
||||
initialize : function(options){
|
||||
this.post = options.post
|
||||
this.comments = new app.collections.Comments(this.get("comments"), {post : this.post})
|
||||
this.post = options.post;
|
||||
this.comments = new app.collections.Comments(this.get("comments"), {post : this.post});
|
||||
this.likes = new app.collections.Likes(this.get("likes"), {post : this.post});
|
||||
this.reshares = new app.collections.Reshares(this.get("reshares"), {post : this.post});
|
||||
},
|
||||
|
||||
parse : function(resp){
|
||||
this.comments.reset(resp.comments)
|
||||
this.likes.reset(resp.likes)
|
||||
this.reshares.reset(resp.reshares)
|
||||
this.comments.reset(resp.comments);
|
||||
this.likes.reset(resp.likes);
|
||||
this.reshares.reset(resp.reshares);
|
||||
|
||||
var comments = this.comments
|
||||
, likes = this.likes
|
||||
, reshares = this.reshares
|
||||
, reshares = this.reshares;
|
||||
|
||||
return {
|
||||
comments : comments,
|
||||
likes : likes,
|
||||
reshares : reshares,
|
||||
fetched : true
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
likesCount : function(){
|
||||
return (this.get("fetched") ? this.likes.models.length : this.get("likes_count") )
|
||||
return (this.get("fetched") ? this.likes.models.length : this.get("likes_count") );
|
||||
},
|
||||
|
||||
resharesCount : function(){
|
||||
return this.get("fetched") ? this.reshares.models.length : this.get("reshares_count")
|
||||
return this.get("fetched") ? this.reshares.models.length : this.get("reshares_count");
|
||||
},
|
||||
|
||||
commentsCount : function(){
|
||||
return this.get("fetched") ? this.comments.models.length : this.get("comments_count")
|
||||
return this.get("fetched") ? this.comments.models.length : this.get("comments_count");
|
||||
},
|
||||
|
||||
userLike : function(){
|
||||
return this.likes.select(function(like){ return like.get("author").guid == app.currentUser.get("guid")})[0]
|
||||
return this.likes.select(function(like){ return like.get("author").guid === app.currentUser.get("guid")})[0];
|
||||
},
|
||||
|
||||
userReshare : function(){
|
||||
return this.reshares.select(function(reshare){
|
||||
return reshare.get("author") && reshare.get("author").guid == app.currentUser.get("guid")})[0]
|
||||
return reshare.get("author") && reshare.get("author").guid === app.currentUser.get("guid")})[0];
|
||||
},
|
||||
|
||||
toggleLike : function() {
|
||||
if(this.userLike()) {
|
||||
this.unlike()
|
||||
this.unlike();
|
||||
} else {
|
||||
this.like()
|
||||
this.like();
|
||||
}
|
||||
},
|
||||
|
||||
like : function() {
|
||||
var self = this;
|
||||
this.likes.create({}, {success : function(){
|
||||
self.trigger("change")
|
||||
self.set({"likes_count" : self.get("likes_count") + 1})
|
||||
}})
|
||||
self.trigger("change");
|
||||
self.set({"likes_count" : self.get("likes_count") + 1});
|
||||
}});
|
||||
|
||||
app.instrument("track", "Like")
|
||||
app.instrument("track", "Like");
|
||||
},
|
||||
|
||||
unlike : function() {
|
||||
var self = this;
|
||||
this.userLike().destroy({success : function(model, resp) {
|
||||
self.trigger('change')
|
||||
self.set({"likes_count" : self.get("likes_count") - 1})
|
||||
this.userLike().destroy({success : function() {
|
||||
self.trigger('change');
|
||||
self.set({"likes_count" : self.get("likes_count") - 1});
|
||||
}});
|
||||
|
||||
app.instrument("track", "Unlike")
|
||||
app.instrument("track", "Unlike");
|
||||
},
|
||||
|
||||
comment : function (text) {
|
||||
var self = this;
|
||||
|
||||
this.comments.make(text).fail(function () {
|
||||
flash = new Diaspora.Widgets.FlashMessages;
|
||||
var flash = new Diaspora.Widgets.FlashMessages();
|
||||
flash.render({
|
||||
success: false,
|
||||
notice: Diaspora.I18n.t("failed_to_post_message")
|
||||
});
|
||||
}).done(function() {
|
||||
self.trigger('change') //updates after sync
|
||||
self.trigger('change'); //updates after sync
|
||||
});
|
||||
|
||||
this.trigger("change") //updates count in an eager manner
|
||||
this.trigger("change"); //updates count in an eager manner
|
||||
|
||||
app.instrument("track", "Comment")
|
||||
app.instrument("track", "Comment");
|
||||
},
|
||||
|
||||
reshare : function(){
|
||||
var interactions = this
|
||||
, reshare = this.post.reshare()
|
||||
, flash = new Diaspora.Widgets.FlashMessages;
|
||||
, flash = new Diaspora.Widgets.FlashMessages();
|
||||
|
||||
reshare.save({}, {
|
||||
success : function(resp){
|
||||
reshare.save()
|
||||
.done(function(reshare) {
|
||||
flash.render({
|
||||
success: true,
|
||||
notice: Diaspora.I18n.t("reshares.successful")
|
||||
});
|
||||
},
|
||||
error: function(resp){
|
||||
interactions.reshares.add(reshare);
|
||||
if (app.stream && /^\/(?:stream|activity|aspects)/.test(app.stream.basePath())) {
|
||||
app.stream.addNow(reshare);
|
||||
}
|
||||
interactions.trigger("change");
|
||||
})
|
||||
.fail(function(){
|
||||
flash.render({
|
||||
success: false,
|
||||
notice: Diaspora.I18n.t("reshares.duplicate")
|
||||
});
|
||||
}
|
||||
}).done(function(){
|
||||
interactions.reshares.add(reshare)
|
||||
}).done(function(){
|
||||
interactions.trigger("change")
|
||||
});
|
||||
|
||||
app.instrument("track", "Reshare")
|
||||
app.instrument("track", "Reshare");
|
||||
},
|
||||
|
||||
userCanReshare : function(){
|
||||
var isReshare = this.post.get("post_type") == "Reshare"
|
||||
var isReshare = this.post.get("post_type") === "Reshare"
|
||||
, rootExists = (isReshare ? this.post.get("root") : true)
|
||||
, publicPost = this.post.get("public")
|
||||
, userIsNotAuthor = this.post.get("author").diaspora_id != app.currentUser.get("diaspora_id")
|
||||
, userIsNotRootAuthor = rootExists && (isReshare ? this.post.get("root").author.diaspora_id != app.currentUser.get("diaspora_id") : true)
|
||||
, userIsNotAuthor = this.post.get("author").diaspora_id !== app.currentUser.get("diaspora_id")
|
||||
, userIsNotRootAuthor = rootExists && (isReshare ? this.post.get("root").author.diaspora_id !== app.currentUser.get("diaspora_id") : true)
|
||||
, notReshared = !this.userReshare();
|
||||
|
||||
return publicPost && app.currentUser.authenticated() && userIsNotAuthor && userIsNotRootAuthor && notReshared;
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,20 +1,24 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.Profile = Backbone.Model.extend({
|
||||
urlRoot : "/profiles"
|
||||
}, {
|
||||
|
||||
preloadOrFetch : function(id){
|
||||
return app.hasPreload("person") ? this.preload() : this.findByGuid(id)
|
||||
return app.hasPreload("person") ? this.preload() : this.findByGuid(id);
|
||||
},
|
||||
|
||||
preload : function(){
|
||||
var person = new app.models.Profile(app.parsePreload("person"))
|
||||
person.deferred = $.when(true)
|
||||
return person
|
||||
var person = new app.models.Profile(app.parsePreload("person"));
|
||||
person.deferred = $.when(true);
|
||||
return person;
|
||||
},
|
||||
|
||||
findByGuid : function(personId){
|
||||
var person = new app.models.Profile({ id : personId})
|
||||
person.deferred = person.fetch()
|
||||
return person
|
||||
var person = new app.models.Profile({ id : personId});
|
||||
person.deferred = person.fetch();
|
||||
return person;
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.Report = Backbone.Model.extend({
|
||||
urlRoot: '/report',
|
||||
type: 'POST'
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,20 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.Reshare = app.models.Post.extend({
|
||||
urlRoot : "/reshares",
|
||||
|
||||
rootPost : function(){
|
||||
this._rootPost = this._rootPost || new app.models.Post(this.get("root"));
|
||||
return this._rootPost
|
||||
return this._rootPost;
|
||||
},
|
||||
|
||||
reshare : function(){
|
||||
return this.rootPost().reshare()
|
||||
return this.rootPost().reshare();
|
||||
},
|
||||
|
||||
reshareAuthor : function(){
|
||||
return this.rootPost().reshareAuthor()
|
||||
return this.rootPost().reshareAuthor();
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.StatusMessage = app.models.Post.extend({
|
||||
url : function(){
|
||||
return this.isNew() ? '/status_messages' : '/posts/' + this.get("id");
|
||||
|
|
@ -15,6 +17,8 @@ app.models.StatusMessage = app.models.Post.extend({
|
|||
photos : this.photos && this.photos.pluck("id"),
|
||||
services : this.get("services"),
|
||||
poll : this.get("poll")
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,49 +1,54 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
//= require ../collections/posts
|
||||
//= require ../collections/photos
|
||||
app.models.Stream = Backbone.Collection.extend({
|
||||
initialize : function(models, options){
|
||||
var collectionClass = options && options.collection || app.collections.Posts;
|
||||
var collectionClass = app.collections.Posts;
|
||||
if( options ) {
|
||||
options.collection && (collectionClass = options.collection);
|
||||
options.basePath && (this.streamPath = options.basePath);
|
||||
}
|
||||
this.items = new collectionClass([], this.collectionOptions());
|
||||
},
|
||||
|
||||
collectionOptions :function(){
|
||||
var order = this.sortOrder();
|
||||
return { comparator : function(item) { return -item[order](); } }
|
||||
return { comparator : function(item) { return -item[order](); } };
|
||||
},
|
||||
|
||||
url : function(){
|
||||
return _.any(this.items.models) ? this.timeFilteredPath() : this.basePath()
|
||||
return _.any(this.items.models) ? this.timeFilteredPath() : this.basePath();
|
||||
},
|
||||
|
||||
_fetchOpts: function(opts) {
|
||||
var defaultOpts = {
|
||||
remove: false // tell backbone to keep existing items in the collection
|
||||
};
|
||||
return _.extend({}, defaultOpts, opts);
|
||||
return _.extend({ url: this.url() }, defaultOpts, opts);
|
||||
},
|
||||
|
||||
fetch: function() {
|
||||
if( this.isFetching() ) return false;
|
||||
var url = this.url();
|
||||
this.deferred = this.items.fetch(this._fetchOpts({url : url}))
|
||||
this.deferred = this.items.fetch( this._fetchOpts() )
|
||||
.done(_.bind(this.triggerFetchedEvents, this));
|
||||
},
|
||||
|
||||
isFetching : function() {
|
||||
return (this.deferred && this.deferred.state() == "pending");
|
||||
return (this.deferred && this.deferred.state() === "pending");
|
||||
},
|
||||
|
||||
triggerFetchedEvents : function(resp){
|
||||
this.trigger("fetched", this);
|
||||
// all loaded?
|
||||
var respItems = this.items.parse(resp);
|
||||
if(respItems && (respItems.author || respItems.length == 0)) {
|
||||
if(respItems && (respItems.author || respItems.length === 0)) {
|
||||
this.trigger("allItemsLoaded", this);
|
||||
}
|
||||
},
|
||||
|
||||
basePath : function(){
|
||||
return document.location.pathname;
|
||||
return this.streamPath || document.location.pathname;
|
||||
},
|
||||
|
||||
timeFilteredPath : function(){
|
||||
|
|
@ -52,11 +57,11 @@ app.models.Stream = Backbone.Collection.extend({
|
|||
|
||||
maxTime: function(){
|
||||
var lastPost = _.last(this.items.models);
|
||||
return lastPost[this.sortOrder()]()
|
||||
return lastPost[this.sortOrder()]();
|
||||
},
|
||||
|
||||
sortOrder : function() {
|
||||
return this.basePath().match(/activity/) ? "interactedAt" : "createdAt"
|
||||
return this.basePath().match(/activity/) ? "interactedAt" : "createdAt";
|
||||
},
|
||||
|
||||
/* This function is for adding a large number of posts one by one.
|
||||
|
|
@ -66,7 +71,7 @@ app.models.Stream = Backbone.Collection.extend({
|
|||
* stream for the changes to take effect in the infinite stream view
|
||||
*/
|
||||
add : function(models){
|
||||
this.items.add(models)
|
||||
this.items.add(models);
|
||||
},
|
||||
|
||||
/* This function is for adding a single post. It immediately triggers
|
||||
|
|
@ -79,12 +84,13 @@ app.models.Stream = Backbone.Collection.extend({
|
|||
},
|
||||
|
||||
preloadOrFetch : function(){ //hai, plz test me THNX
|
||||
return $.when(app.hasPreload("stream") ? this.preload() : this.fetch())
|
||||
return $.when(app.hasPreload("stream") ? this.preload() : this.fetch());
|
||||
},
|
||||
|
||||
preload : function(){
|
||||
this.items.reset(app.parsePreload("stream"))
|
||||
this.deferred = $.when(true)
|
||||
this.trigger("fetched")
|
||||
this.items.reset(app.parsePreload("stream"));
|
||||
this.deferred = $.when(true);
|
||||
this.trigger("fetched");
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.StreamAspects = app.models.Stream.extend({
|
||||
|
||||
url : function(){
|
||||
return _.any(this.items.models) ? this.timeFilteredPath() : this.basePath()
|
||||
return _.any(this.items.models) ? this.timeFilteredPath() : this.basePath();
|
||||
},
|
||||
|
||||
initialize : function(models, options){
|
||||
|
|
@ -19,6 +21,15 @@ app.models.StreamAspects = app.models.Stream.extend({
|
|||
var url = this.url();
|
||||
var ids = this.aspects_ids;
|
||||
this.deferred = this.items.fetch(this._fetchOpts({url : url, data : { 'a_ids': ids }}))
|
||||
.done(_.bind(this.triggerFetchedEvents, this));
|
||||
.done(_.bind(this.fetchDone, this));
|
||||
},
|
||||
|
||||
fetchDone: function() {
|
||||
this.triggerFetchedEvents();
|
||||
if (app.aspects) {
|
||||
app.aspects.trigger('aspectStreamFetched');
|
||||
}
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.TagFollowing = Backbone.Model.extend({
|
||||
urlRoot: "/tag_followings"
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.models.User = Backbone.Model.extend({
|
||||
toggleNsfwState : function() {
|
||||
if(!app.currentUser.authenticated()){ return false }
|
||||
|
|
@ -10,14 +12,16 @@ app.models.User = Backbone.Model.extend({
|
|||
},
|
||||
|
||||
expProfileUrl : function(){
|
||||
return "/people/" + app.currentUser.get("guid") + "?ex=true"
|
||||
return "/people/" + app.currentUser.get("guid") + "?ex=true";
|
||||
},
|
||||
|
||||
isServiceConfigured : function(providerName) {
|
||||
return _.include(this.get("configured_services"), providerName)
|
||||
return _.include(this.get("configured_services"), providerName);
|
||||
},
|
||||
|
||||
isAuthorOf: function(model) {
|
||||
return this.authenticated() && model.get("author").id == this.id;
|
||||
return this.authenticated() && model.get("author").id === this.id;
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
75
app/assets/javascripts/app/pages/contacts.js
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.pages.Contacts = Backbone.View.extend({
|
||||
|
||||
el: "#contacts_container",
|
||||
|
||||
events: {
|
||||
"click #contacts_visibility_toggle" : "toggleContactVisibility",
|
||||
"click #chat_privilege_toggle" : "toggleChatPrivilege",
|
||||
"click #change_aspect_name" : "showAspectNameForm",
|
||||
"keyup #contact_list_search" : "searchContactList"
|
||||
},
|
||||
|
||||
initialize: function(opts) {
|
||||
this.visibility_toggle = $("#contacts_visibility_toggle .entypo");
|
||||
this.chat_toggle = $("#chat_privilege_toggle .entypo");
|
||||
this.stream = opts.stream;
|
||||
this.stream.render();
|
||||
$("#people_stream.contacts .header .entypo").tooltip({ 'placement': 'bottom'});
|
||||
$(document).on('ajax:success', 'form.edit_aspect', this.updateAspectName);
|
||||
},
|
||||
|
||||
toggleChatPrivilege: function() {
|
||||
if (this.chat_toggle.hasClass("enabled")) {
|
||||
this.chat_toggle.tooltip("destroy")
|
||||
.removeClass("enabled")
|
||||
.removeAttr("data-original-title")
|
||||
.attr("title", Diaspora.I18n.t("contacts.aspect_chat_is_not_enabled"))
|
||||
.tooltip({'placement': 'bottom'});
|
||||
} else {
|
||||
this.chat_toggle.tooltip("destroy")
|
||||
.addClass("enabled")
|
||||
.removeAttr("data-original-title")
|
||||
.attr("title", Diaspora.I18n.t("contacts.aspect_chat_is_enabled"))
|
||||
.tooltip({'placement': 'bottom'});
|
||||
}
|
||||
},
|
||||
|
||||
toggleContactVisibility: function() {
|
||||
if (this.visibility_toggle.hasClass("lock-open")) {
|
||||
this.visibility_toggle.removeClass("lock-open")
|
||||
.addClass("lock")
|
||||
.tooltip("destroy")
|
||||
.removeAttr("data-original-title")
|
||||
.attr("title", Diaspora.I18n.t("contacts.aspect_list_is_not_visible"))
|
||||
.tooltip({'placement': 'bottom'});
|
||||
}
|
||||
else {
|
||||
this.visibility_toggle.removeClass("lock")
|
||||
.addClass("lock-open")
|
||||
.tooltip("destroy")
|
||||
.removeAttr("data-original-title")
|
||||
.attr("title", Diaspora.I18n.t("contacts.aspect_list_is_visible"))
|
||||
.tooltip({'placement': 'bottom'});
|
||||
}
|
||||
},
|
||||
|
||||
showAspectNameForm: function() {
|
||||
$(".header > h3").hide();
|
||||
$(".header > #aspect_name_form").show();
|
||||
},
|
||||
|
||||
updateAspectName: function(evt,data){
|
||||
$(".header #aspect_name").text(data['name']);
|
||||
$("#aspect_nav [data-aspect-id='"+data['id']+"'] .name").text(data['name']);
|
||||
$(".header > #aspect_name_form").hide();
|
||||
$(".header > h3").show();
|
||||
},
|
||||
|
||||
searchContactList: function(e) {
|
||||
this.stream.search($(e.target).val());
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
130
app/assets/javascripts/app/pages/profile.js
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.pages.Profile = app.views.Base.extend({
|
||||
events: {
|
||||
'click #block_user_button': 'blockPerson',
|
||||
'click #unblock_user_button': 'unblockPerson'
|
||||
},
|
||||
|
||||
subviews: {
|
||||
'#profile': 'sidebarView',
|
||||
'.profile_header': 'headerView',
|
||||
'#main_stream': 'streamView'
|
||||
},
|
||||
|
||||
tooltipSelector: '.profile_button .profile-header-icon, .sharing_message_container',
|
||||
|
||||
initialize: function(opts) {
|
||||
if( !this.model ) {
|
||||
this._populateModel(opts);
|
||||
}
|
||||
|
||||
if( app.hasPreload('photos') )
|
||||
this.photos = app.parsePreload('photos'); // we don't interact with it, so no model
|
||||
if( app.hasPreload('contacts') )
|
||||
this.contacts = app.parsePreload('contacts'); // we don't interact with it, so no model
|
||||
|
||||
this.streamCollection = _.has(opts, 'streamCollection') ? opts.streamCollection : null;
|
||||
this.streamViewClass = _.has(opts, 'streamView') ? opts.streamView : null;
|
||||
|
||||
this.model.on('change', this.render, this);
|
||||
this.model.on('sync', this._done, this);
|
||||
|
||||
// bind to global events
|
||||
var id = this.model.get('id');
|
||||
app.events.on('person:block:'+id, this.reload, this);
|
||||
app.events.on('person:unblock:'+id, this.reload, this);
|
||||
app.events.on('aspect:create', this.reload, this);
|
||||
app.events.on('aspect_membership:update', this.reload, this);
|
||||
},
|
||||
|
||||
_populateModel: function(opts) {
|
||||
if( app.hasPreload('person') ) {
|
||||
this.model = new app.models.Person(app.parsePreload('person'));
|
||||
} else if(opts && opts.person_id) {
|
||||
this.model = new app.models.Person({guid: opts.person_id});
|
||||
this.model.fetch();
|
||||
} else {
|
||||
throw new Error("unable to load person");
|
||||
}
|
||||
},
|
||||
|
||||
sidebarView: function() {
|
||||
if( !this.model.has('profile') ) return false;
|
||||
return new app.views.ProfileSidebar({
|
||||
model: this.model,
|
||||
});
|
||||
},
|
||||
|
||||
headerView: function() {
|
||||
if( !this.model.has('profile') ) return false;
|
||||
return new app.views.ProfileHeader({
|
||||
model: this.model,
|
||||
photos: this.photos,
|
||||
contacts: this.contacts
|
||||
});
|
||||
},
|
||||
|
||||
streamView: function() {
|
||||
if( !this.model.has('profile') ) return false;
|
||||
if( this.model.isBlocked() ) {
|
||||
$('#main_stream').empty().html(
|
||||
'<div class="dull">'+
|
||||
Diaspora.I18n.t('profile.ignoring', {name: this.model.get('name')}) +
|
||||
'</div>');
|
||||
return false;
|
||||
}
|
||||
|
||||
// a collection is set, this means we want to view photos
|
||||
var route = this.streamCollection ? 'person_photos_path' : 'person_stream_path';
|
||||
var view = this.streamViewClass ? this.streamViewClass : app.views.Stream;
|
||||
|
||||
app.stream = new app.models.Stream(null, {
|
||||
basePath: Routes[route](app.page.model.get('guid')),
|
||||
collection: this.streamCollection
|
||||
});
|
||||
app.stream.fetch();
|
||||
|
||||
if( this.model.get('is_own_profile') ) {
|
||||
app.publisher = new app.views.Publisher({collection : app.stream.items});
|
||||
}
|
||||
|
||||
return new view({model: app.stream});
|
||||
},
|
||||
|
||||
blockPerson: function() {
|
||||
if( !confirm(Diaspora.I18n.t('ignore_user')) ) return;
|
||||
|
||||
var block = this.model.block();
|
||||
block.fail(function() {
|
||||
Diaspora.page.flashMessages.render({
|
||||
success: false,
|
||||
notice: Diaspora.I18n.t('ignore_failed')
|
||||
});
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
unblockPerson: function() {
|
||||
var block = this.model.unblock();
|
||||
block.fail(function() {
|
||||
Diaspora.page.flashMessages.render({
|
||||
success: false,
|
||||
notice: Diaspora.I18.t('unblock_failed')
|
||||
});
|
||||
});
|
||||
return false;
|
||||
},
|
||||
|
||||
reload: function() {
|
||||
this.$('#profile').addClass('loading');
|
||||
this.model.fetch();
|
||||
},
|
||||
|
||||
_done: function() {
|
||||
this.$('#profile').removeClass('loading');
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.pages.SinglePostViewer = app.views.Base.extend({
|
||||
templateName: "single-post-viewer",
|
||||
|
||||
|
|
@ -9,8 +11,8 @@ app.pages.SinglePostViewer = app.views.Base.extend({
|
|||
initialize : function(options) {
|
||||
this.model = new app.models.Post({ id : options.id });
|
||||
this.model.preloadOrFetch().done(_.bind(this.initViews, this));
|
||||
this.model.interactions.fetch() //async, yo, might want to throttle this later.
|
||||
this.setupLightbox()
|
||||
this.model.interactions.fetch(); //async, yo, might want to throttle this later.
|
||||
this.setupLightbox();
|
||||
},
|
||||
|
||||
setupLightbox : function(){
|
||||
|
|
@ -31,10 +33,11 @@ app.pages.SinglePostViewer = app.views.Base.extend({
|
|||
postRenderTemplate : function() {
|
||||
if(this.model.get("title")){
|
||||
// formats title to html...
|
||||
var html_title = app.helpers.textFormatter(this.model.get("title"), this.model);
|
||||
var html_title = app.helpers.textFormatter(this.model.get("title"), this.model.get("mentioned_people"));
|
||||
//... and converts html to plain text
|
||||
document.title = $('<div>').html(html_title).text();
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,6 +1,12 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.Router = Backbone.Router.extend({
|
||||
routes: {
|
||||
"help/:section": "help",
|
||||
"help/": "help",
|
||||
"help": "help",
|
||||
"contacts": "contacts",
|
||||
"conversations": "conversations",
|
||||
|
||||
//new hotness
|
||||
"posts/:id": "singlePost",
|
||||
|
|
@ -19,11 +25,12 @@ app.Router = Backbone.Router.extend({
|
|||
"followed_tags": "followed_tags",
|
||||
"tags/:name": "followed_tags",
|
||||
"people/:id/photos": "photos",
|
||||
"people/:id/contacts": "profile",
|
||||
|
||||
"people/:id": "stream",
|
||||
"u/:name": "stream"
|
||||
"people/:id": "profile",
|
||||
"u/:name": "profile"
|
||||
},
|
||||
|
||||
|
||||
initialize: function() {
|
||||
// To support encoded linefeeds (%0A) we need to specify
|
||||
// our own internal router.route call with the correct regexp.
|
||||
|
|
@ -31,10 +38,26 @@ app.Router = Backbone.Router.extend({
|
|||
this.route(/^bookmarklet(?:\?(.*))?/, "bookmarklet");
|
||||
},
|
||||
|
||||
help: function() {
|
||||
help: function(section) {
|
||||
app.help = new app.views.Help();
|
||||
$("#help").prepend(app.help.el);
|
||||
app.help.render();
|
||||
app.help.render(section);
|
||||
},
|
||||
|
||||
contacts: function() {
|
||||
app.aspect = new app.models.Aspect(gon.preloads.aspect);
|
||||
app.contacts = new app.collections.Contacts(app.parsePreload('contacts'));
|
||||
|
||||
var stream = new app.views.ContactStream({
|
||||
collection: app.contacts,
|
||||
el: $('.stream.contacts #contact_stream'),
|
||||
});
|
||||
|
||||
app.page = new app.pages.Contacts({stream: stream});
|
||||
},
|
||||
|
||||
conversations: function() {
|
||||
app.conversations = new app.views.Conversations();
|
||||
},
|
||||
|
||||
singlePost : function(id) {
|
||||
|
|
@ -42,14 +65,19 @@ app.Router = Backbone.Router.extend({
|
|||
},
|
||||
|
||||
renderPage : function(pageConstructor){
|
||||
app.page && app.page.unbind && app.page.unbind() //old page might mutate global events $(document).keypress, so unbind before creating
|
||||
app.page = pageConstructor() //create new page after the world is clean (like that will ever happen)
|
||||
$("#container").html(app.page.render().el)
|
||||
app.page && app.page.unbind && app.page.unbind(); //old page might mutate global events $(document).keypress, so unbind before creating
|
||||
app.page = pageConstructor(); //create new page after the world is clean (like that will ever happen)
|
||||
app.page.render();
|
||||
|
||||
if( !$.contains(document, app.page.el) ) {
|
||||
// view element isn't already attached to the DOM, insert it
|
||||
$("#container").empty().append(app.page.el);
|
||||
}
|
||||
},
|
||||
|
||||
//below here is oldness
|
||||
|
||||
stream : function(page) {
|
||||
stream : function() {
|
||||
app.stream = new app.models.Stream();
|
||||
app.stream.fetch();
|
||||
app.page = new app.views.Stream({model : app.stream});
|
||||
|
|
@ -59,13 +87,18 @@ app.Router = Backbone.Router.extend({
|
|||
|
||||
$("#main_stream").html(app.page.render().el);
|
||||
$('#selected_aspect_contacts .content').html(streamFacesView.render().el);
|
||||
this.hideInactiveStreamLists();
|
||||
this._hideInactiveStreamLists();
|
||||
},
|
||||
|
||||
photos : function() {
|
||||
app.photos = new app.models.Stream([], {collection: app.collections.Photos});
|
||||
app.page = new app.views.Photos({model : app.photos});
|
||||
$("#main_stream").html(app.page.render().el);
|
||||
photos : function(guid) {
|
||||
this.renderPage(function() {
|
||||
return new app.pages.Profile({
|
||||
person_id: guid,
|
||||
el: $('body > .container-fluid'),
|
||||
streamCollection: app.collections.Photos,
|
||||
streamView: app.views.Photos
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
followed_tags : function(name) {
|
||||
|
|
@ -82,9 +115,10 @@ app.Router = Backbone.Router.extend({
|
|||
var followedTagsAction = new app.views.TagFollowingAction(
|
||||
{tagText: decodeURIComponent(name).toLowerCase()}
|
||||
);
|
||||
$("#author_info").prepend(followedTagsAction.render().el)
|
||||
$("#author_info").prepend(followedTagsAction.render().el);
|
||||
app.tags = new app.views.Tags({tagName: name});
|
||||
}
|
||||
this.hideInactiveStreamLists();
|
||||
this._hideInactiveStreamLists();
|
||||
},
|
||||
|
||||
aspects : function(){
|
||||
|
|
@ -107,22 +141,28 @@ app.Router = Backbone.Router.extend({
|
|||
|
||||
$("#main_stream").html(app.page.render().el);
|
||||
$('#selected_aspect_contacts .content').html(streamFacesView.render().el);
|
||||
this.hideInactiveStreamLists();
|
||||
this._hideInactiveStreamLists();
|
||||
},
|
||||
|
||||
hideInactiveStreamLists: function() {
|
||||
if(this.aspects_list && Backbone.history.fragment != "aspects")
|
||||
_hideInactiveStreamLists: function() {
|
||||
if(this.aspects_list && Backbone.history.fragment !== "aspects")
|
||||
this.aspects_list.hideAspectsList();
|
||||
|
||||
if(this.followedTagsView && Backbone.history.fragment != "followed_tags")
|
||||
if(this.followedTagsView && Backbone.history.fragment !== "followed_tags")
|
||||
this.followedTagsView.hideFollowedTags();
|
||||
},
|
||||
|
||||
bookmarklet: function() {
|
||||
var contents = (window.gon) ? gon.preloads.bookmarklet : {}
|
||||
var contents = (window.gon) ? gon.preloads.bookmarklet : {};
|
||||
app.bookmarklet = new app.views.Bookmarklet(
|
||||
_.extend({}, {el: $('#bookmarklet')}, contents)
|
||||
).render();
|
||||
},
|
||||
|
||||
profile: function() {
|
||||
this.renderPage(function() { return new app.pages.Profile({
|
||||
el: $('body > .container-fluid')
|
||||
}); });
|
||||
}
|
||||
});
|
||||
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Base = Backbone.View.extend({
|
||||
|
||||
initialize : function(options) {
|
||||
initialize : function() {
|
||||
this.setupRenderEvents();
|
||||
},
|
||||
|
||||
presenter : function(){
|
||||
return this.defaultPresenter()
|
||||
return this.defaultPresenter();
|
||||
},
|
||||
|
||||
setupRenderEvents : function(){
|
||||
|
|
@ -16,7 +18,7 @@ app.views.Base = Backbone.View.extend({
|
|||
},
|
||||
|
||||
defaultPresenter : function(){
|
||||
var modelJson = this.model && this.model.attributes ? _.clone(this.model.attributes) : {}
|
||||
var modelJson = this.model && this.model.attributes ? _.clone(this.model.attributes) : {};
|
||||
|
||||
return _.extend(modelJson, {
|
||||
current_user : app.currentUser.attributes,
|
||||
|
|
@ -25,24 +27,29 @@ app.views.Base = Backbone.View.extend({
|
|||
},
|
||||
|
||||
render : function() {
|
||||
this.renderTemplate()
|
||||
this.renderSubviews()
|
||||
this.renderPluginWidgets()
|
||||
this.removeTooltips()
|
||||
this.renderTemplate();
|
||||
this.renderSubviews();
|
||||
this.renderPluginWidgets();
|
||||
this.removeTooltips();
|
||||
|
||||
return this
|
||||
return this;
|
||||
},
|
||||
|
||||
renderTemplate : function(){
|
||||
var presenter = _.isFunction(this.presenter) ? this.presenter() : this.presenter
|
||||
this.template = JST[this.templateName+"_tpl"]
|
||||
var presenter = _.isFunction(this.presenter) ? this.presenter() : this.presenter;
|
||||
this.template = HandlebarsTemplates[this.templateName+"_tpl"];
|
||||
if(!this.template) {
|
||||
console.log(this.templateName ? ("no template for " + this.templateName) : "no templateName specified")
|
||||
console.log(this.templateName ? ("no template for " + this.templateName) : "no templateName specified");
|
||||
return;
|
||||
}
|
||||
|
||||
this.$el
|
||||
.html(this.template(presenter))
|
||||
.attr("data-template", _.last(this.templateName.split("/")));
|
||||
|
||||
// add avatar fallback if it can't be loaded
|
||||
this.$el.find(this.avatars.selector).error(this.avatars.fallback);
|
||||
|
||||
this.postRenderTemplate();
|
||||
},
|
||||
|
||||
|
|
@ -51,12 +58,12 @@ app.views.Base = Backbone.View.extend({
|
|||
renderSubviews : function(){
|
||||
var self = this;
|
||||
_.each(this.subviews, function(property, selector){
|
||||
var view = _.isFunction(self[property]) ? self[property]() : self[property]
|
||||
var view = _.isFunction(self[property]) ? self[property]() : self[property];
|
||||
if(view) {
|
||||
self.$(selector).html(view.render().el)
|
||||
self.$(selector).html(view.render().el);
|
||||
view.delegateEvents();
|
||||
}
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
renderPluginWidgets : function() {
|
||||
|
|
@ -69,16 +76,16 @@ app.views.Base = Backbone.View.extend({
|
|||
},
|
||||
|
||||
setFormAttrs : function(){
|
||||
this.model.set(_.inject(this.formAttrs, _.bind(setValueFromField, this), {}))
|
||||
|
||||
function setValueFromField(memo, attribute, selector){
|
||||
if(attribute.slice("-2") === "[]") {
|
||||
memo[attribute.slice(0, attribute.length - 2)] = _.pluck(this.$el.find(selector).serializeArray(), "value")
|
||||
memo[attribute.slice(0, attribute.length - 2)] = _.pluck(this.$el.find(selector).serializeArray(), "value");
|
||||
} else {
|
||||
memo[attribute] = this.$el.find(selector).val() || this.$el.find(selector).text();
|
||||
}
|
||||
return memo
|
||||
return memo;
|
||||
}
|
||||
|
||||
this.model.set(_.inject(this.formAttrs, _.bind(setValueFromField, this), {}));
|
||||
},
|
||||
|
||||
report: function(evt) {
|
||||
|
|
@ -97,13 +104,13 @@ app.views.Base = Backbone.View.extend({
|
|||
|
||||
var report = new app.models.Report();
|
||||
report.save(data, {
|
||||
success: function(model, response) {
|
||||
success: function() {
|
||||
Diaspora.page.flashMessages.render({
|
||||
success: true,
|
||||
notice: Diaspora.I18n.t('report.status.created')
|
||||
});
|
||||
},
|
||||
error: function(model, response) {
|
||||
error: function() {
|
||||
Diaspora.page.flashMessages.render({
|
||||
success: false,
|
||||
notice: Diaspora.I18n.t('report.status.exists')
|
||||
|
|
@ -118,12 +125,14 @@ app.views.Base = Backbone.View.extend({
|
|||
var url = this.model.urlRoot + '/' + this.model.id;
|
||||
|
||||
if (confirm(Diaspora.I18n.t("confirm_dialog"))) {
|
||||
this.$el.addClass('deleting');
|
||||
this.model.destroy({ url: url })
|
||||
.done(function() {
|
||||
self.remove();
|
||||
})
|
||||
.fail(function() {
|
||||
var flash = new Diaspora.Widgets.FlashMessages;
|
||||
self.$el.removeClass('deleting');
|
||||
var flash = new Diaspora.Widgets.FlashMessages();
|
||||
flash.render({
|
||||
success: false,
|
||||
notice: Diaspora.I18n.t('failed_to_remove')
|
||||
|
|
@ -131,6 +140,13 @@ app.views.Base = Backbone.View.extend({
|
|||
});
|
||||
}
|
||||
},
|
||||
|
||||
avatars: {
|
||||
fallback: function() {
|
||||
$(this).attr("src", ImagePaths.get("user/default.png"));
|
||||
},
|
||||
selector: "img.avatar"
|
||||
}
|
||||
});
|
||||
|
||||
app.views.StaticContentView = app.views.Base.extend({
|
||||
|
|
@ -146,3 +162,4 @@ app.views.StaticContentView = app.views.Base.extend({
|
|||
return this.data;
|
||||
},
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,161 +0,0 @@
|
|||
/**
|
||||
* this view lets the user (de-)select aspect memberships in the context
|
||||
* of another users profile or the contact page.
|
||||
*
|
||||
* updates to the list of aspects are immediately propagated to the server, and
|
||||
* the results are dislpayed as flash messages.
|
||||
*/
|
||||
app.views.AspectMembershipBlueprint = Backbone.View.extend({
|
||||
|
||||
initialize: function() {
|
||||
// attach event handler, removing any previous instances
|
||||
var selector = '.dropdown.aspect_membership .dropdown_list > li';
|
||||
$('body')
|
||||
.off('click', selector)
|
||||
.on('click', selector, _.bind(this._clickHandler, this));
|
||||
|
||||
this.list_item = null;
|
||||
this.dropdown = null;
|
||||
},
|
||||
|
||||
// decide what to do when clicked
|
||||
// -> addMembership
|
||||
// -> removeMembership
|
||||
_clickHandler: function(evt) {
|
||||
this.list_item = $(evt.target);
|
||||
this.dropdown = this.list_item.parent();
|
||||
|
||||
this.list_item.addClass('loading');
|
||||
|
||||
if( this.list_item.is('.selected') ) {
|
||||
var membership_id = this.list_item.data('membership_id');
|
||||
this.removeMembership(membership_id);
|
||||
} else {
|
||||
var aspect_id = this.list_item.data('aspect_id');
|
||||
var person_id = this.dropdown.data('person_id');
|
||||
this.addMembership(person_id, aspect_id);
|
||||
}
|
||||
|
||||
return false; // stop the event
|
||||
},
|
||||
|
||||
// return the (short) name of the person associated with the current dropdown
|
||||
_name: function() {
|
||||
return this.dropdown.data('person-short-name');
|
||||
},
|
||||
|
||||
// create a membership for the given person in the given aspect
|
||||
addMembership: function(person_id, aspect_id) {
|
||||
var aspect_membership = new app.models.AspectMembership({
|
||||
'person_id': person_id,
|
||||
'aspect_id': aspect_id
|
||||
});
|
||||
|
||||
aspect_membership.on('sync', this._successSaveCb, this);
|
||||
aspect_membership.on('error', function() {
|
||||
this._displayError('aspect_dropdown.error');
|
||||
}, this);
|
||||
|
||||
aspect_membership.save();
|
||||
},
|
||||
|
||||
_successSaveCb: function(aspect_membership) {
|
||||
var aspect_id = aspect_membership.get('aspect_id');
|
||||
var membership_id = aspect_membership.get('id');
|
||||
var li = this.dropdown.find('li[data-aspect_id="'+aspect_id+'"]');
|
||||
|
||||
// the user didn't have this person in any aspects before, congratulate them
|
||||
// on their newly found friendship ;)
|
||||
if( this.dropdown.find('li.selected').length == 0 ) {
|
||||
var msg = Diaspora.I18n.t('aspect_dropdown.started_sharing_with', { 'name': this._name() });
|
||||
Diaspora.page.flashMessages.render({ 'success':true, 'notice':msg });
|
||||
}
|
||||
|
||||
li.attr('data-membership_id', membership_id) // just to be sure...
|
||||
.data('membership_id', membership_id)
|
||||
.addClass('selected');
|
||||
|
||||
this.updateSummary();
|
||||
this._done();
|
||||
},
|
||||
|
||||
// show an error flash msg
|
||||
_displayError: function(msg_id) {
|
||||
this._done();
|
||||
this.dropdown.removeClass('active'); // close the dropdown
|
||||
|
||||
var msg = Diaspora.I18n.t(msg_id, { 'name': this._name() });
|
||||
Diaspora.page.flashMessages.render({ 'success':false, 'notice':msg });
|
||||
},
|
||||
|
||||
// remove the membership with the given id
|
||||
removeMembership: function(membership_id) {
|
||||
var aspect_membership = new app.models.AspectMembership({
|
||||
'id': membership_id
|
||||
});
|
||||
|
||||
aspect_membership.on('sync', this._successDestroyCb, this);
|
||||
aspect_membership.on('error', function() {
|
||||
this._displayError('aspect_dropdown.error_remove');
|
||||
}, this);
|
||||
|
||||
aspect_membership.destroy();
|
||||
},
|
||||
|
||||
_successDestroyCb: function(aspect_membership) {
|
||||
var membership_id = aspect_membership.get('id');
|
||||
var li = this.dropdown.find('li[data-membership_id="'+membership_id+'"]');
|
||||
|
||||
li.removeAttr('data-membership_id')
|
||||
.removeData('membership_id')
|
||||
.removeClass('selected');
|
||||
|
||||
// we just removed the last aspect, inform the user with a flash message
|
||||
// that he is no longer sharing with that person
|
||||
if( this.dropdown.find('li.selected').length == 0 ) {
|
||||
var msg = Diaspora.I18n.t('aspect_dropdown.stopped_sharing_with', { 'name': this._name() });
|
||||
Diaspora.page.flashMessages.render({ 'success':true, 'notice':msg });
|
||||
}
|
||||
|
||||
this.updateSummary();
|
||||
this._done();
|
||||
},
|
||||
|
||||
// cleanup tasks after aspect selection
|
||||
_done: function() {
|
||||
if( this.list_item ) {
|
||||
this.list_item.removeClass('loading');
|
||||
}
|
||||
},
|
||||
|
||||
// refresh the button text to reflect the current aspect selection status
|
||||
updateSummary: function() {
|
||||
var btn = this.dropdown.parents('div.aspect_membership').find('.button.toggle');
|
||||
var aspects_cnt = this.dropdown.find('li.selected').length;
|
||||
var txt;
|
||||
|
||||
if( aspects_cnt == 0 ) {
|
||||
btn.removeClass('in_aspects');
|
||||
txt = Diaspora.I18n.t('aspect_dropdown.toggle.zero');
|
||||
} else {
|
||||
btn.addClass('in_aspects');
|
||||
txt = this._pluralSummaryTxt(aspects_cnt);
|
||||
}
|
||||
|
||||
btn.text(txt + ' ▼');
|
||||
},
|
||||
|
||||
_pluralSummaryTxt: function(cnt) {
|
||||
var all_aspects_cnt = this.dropdown.find('li').length;
|
||||
|
||||
if( cnt == 1 ) {
|
||||
return this.dropdown.find('li.selected').first().text();
|
||||
}
|
||||
|
||||
if( cnt == all_aspects_cnt ) {
|
||||
return Diaspora.I18n.t('aspect_dropdown.all_aspects');
|
||||
}
|
||||
|
||||
return Diaspora.I18n.t('aspect_dropdown.toggle', { 'count':cnt.toString() });
|
||||
}
|
||||
});
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
//= require ./aspects_dropdown_view
|
||||
|
||||
/**
|
||||
|
|
@ -10,7 +12,8 @@
|
|||
app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
||||
|
||||
events: {
|
||||
"click ul.aspect_membership.dropdown-menu > li.aspect_selector": "_clickHandler"
|
||||
"click ul.aspect_membership.dropdown-menu > li.aspect_selector": "_clickHandler",
|
||||
"keypress ul.aspect_membership.dropdown-menu > li.aspect_selector": "_clickHandler"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
|
|
@ -22,6 +25,7 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
|||
// -> addMembership
|
||||
// -> removeMembership
|
||||
_clickHandler: function(evt) {
|
||||
var promise = null;
|
||||
this.list_item = $(evt.target).closest('li.aspect_selector');
|
||||
this.dropdown = this.list_item.parent();
|
||||
|
||||
|
|
@ -29,13 +33,18 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
|||
|
||||
if( this.list_item.is('.selected') ) {
|
||||
var membership_id = this.list_item.data('membership_id');
|
||||
this.removeMembership(membership_id);
|
||||
promise = this.removeMembership(membership_id);
|
||||
} else {
|
||||
var aspect_id = this.list_item.data('aspect_id');
|
||||
var person_id = this.dropdown.data('person_id');
|
||||
this.addMembership(person_id, aspect_id);
|
||||
promise = this.addMembership(person_id, aspect_id);
|
||||
}
|
||||
|
||||
promise && promise.always(function() {
|
||||
// trigger a global event
|
||||
app.events.trigger('aspect_membership:update');
|
||||
});
|
||||
|
||||
return false; // stop the event
|
||||
},
|
||||
|
||||
|
|
@ -56,7 +65,7 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
|||
this._displayError('aspect_dropdown.error');
|
||||
}, this);
|
||||
|
||||
aspect_membership.save();
|
||||
return aspect_membership.save();
|
||||
},
|
||||
|
||||
_successSaveCb: function(aspect_membership) {
|
||||
|
|
@ -66,7 +75,7 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
|||
|
||||
// the user didn't have this person in any aspects before, congratulate them
|
||||
// on their newly found friendship ;)
|
||||
if( this.dropdown.find('li.selected').length == 0 ) {
|
||||
if( this.dropdown.find('li.selected').length === 0 ) {
|
||||
var msg = Diaspora.I18n.t('aspect_dropdown.started_sharing_with', { 'name': this._name() });
|
||||
Diaspora.page.flashMessages.render({ 'success':true, 'notice':msg });
|
||||
}
|
||||
|
|
@ -98,7 +107,7 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
|||
this._displayError('aspect_dropdown.error_remove');
|
||||
}, this);
|
||||
|
||||
aspect_membership.destroy();
|
||||
return aspect_membership.destroy();
|
||||
},
|
||||
|
||||
_successDestroyCb: function(aspect_membership) {
|
||||
|
|
@ -111,7 +120,7 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
|||
|
||||
// we just removed the last aspect, inform the user with a flash message
|
||||
// that he is no longer sharing with that person
|
||||
if( this.dropdown.find('li.selected').length == 0 ) {
|
||||
if( this.dropdown.find('li.selected').length === 0 ) {
|
||||
var msg = Diaspora.I18n.t('aspect_dropdown.stopped_sharing_with', { 'name': this._name() });
|
||||
Diaspora.page.flashMessages.render({ 'success':true, 'notice':msg });
|
||||
}
|
||||
|
|
@ -132,3 +141,5 @@ app.views.AspectMembership = app.views.AspectsDropdown.extend({
|
|||
this._updateButton('green');
|
||||
},
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Aspect = app.views.Base.extend({
|
||||
templateName: "aspect",
|
||||
|
||||
|
|
@ -6,19 +8,20 @@ app.views.Aspect = app.views.Base.extend({
|
|||
className: 'hoverable',
|
||||
|
||||
events: {
|
||||
'click .icons-check_yes_ok+a': 'toggleAspect'
|
||||
'click .entypo.check+a': 'toggleAspect'
|
||||
},
|
||||
|
||||
toggleAspect: function(evt) {
|
||||
if (evt) { evt.preventDefault(); };
|
||||
if (evt) { evt.preventDefault(); }
|
||||
this.model.toggleSelected();
|
||||
this.$el.find('.icons-check_yes_ok').toggleClass('selected');
|
||||
|
||||
app.router.aspects_stream();
|
||||
},
|
||||
|
||||
presenter : function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
aspect : this.model
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
/*
|
||||
* Aspects view for the publishers aspect dropdown and the aspect membership dropdown.
|
||||
*/
|
||||
|
|
@ -14,12 +16,11 @@ app.views.AspectsDropdown = app.views.Base.extend({
|
|||
|
||||
// select aspects in the dropdown by a given list of ids
|
||||
_selectAspects: function(ids) {
|
||||
this.$('.dropdown-menu > li').each(function(){
|
||||
this.$('.dropdown-menu > li').each(function() {
|
||||
var el = $(this);
|
||||
if(_.contains(ids, el.data('aspect_id'))){
|
||||
if (_.contains(ids, el.data('aspect_id'))) {
|
||||
el.addClass('selected');
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
el.removeClass('selected');
|
||||
}
|
||||
});
|
||||
|
|
@ -31,16 +32,14 @@ app.views.AspectsDropdown = app.views.Base.extend({
|
|||
selectedAspects = this.$(".dropdown-menu > li.selected").length,
|
||||
buttonText;
|
||||
|
||||
if(selectedAspects == 0){
|
||||
if (selectedAspects === 0) {
|
||||
button.removeClass(inAspectClass).addClass('btn-default');
|
||||
buttonText = Diaspora.I18n.t("aspect_dropdown.select_aspects");
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
button.removeClass('btn-default').addClass(inAspectClass);
|
||||
if(selectedAspects == 1){
|
||||
if (selectedAspects === 1) {
|
||||
buttonText = this.$(".dropdown-menu > li.selected .text").first().text();
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
buttonText = Diaspora.I18n.t("aspect_dropdown.toggle", { count: selectedAspects.toString() });
|
||||
}
|
||||
}
|
||||
|
|
@ -48,3 +47,5 @@ app.views.AspectsDropdown = app.views.Base.extend({
|
|||
button.find('.text').text(buttonText);
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.AspectsList = app.views.Base.extend({
|
||||
templateName: 'aspects-list',
|
||||
|
||||
|
|
@ -10,6 +12,7 @@ app.views.AspectsList = app.views.Base.extend({
|
|||
initialize: function() {
|
||||
this.collection.on('change', this.toggleSelector, this);
|
||||
this.collection.on('change', this.updateStreamTitle, this);
|
||||
this.collection.on('aspectStreamFetched', this.updateAspectList, this);
|
||||
},
|
||||
|
||||
postRenderTemplate: function() {
|
||||
|
|
@ -26,19 +29,12 @@ app.views.AspectsList = app.views.Base.extend({
|
|||
},
|
||||
|
||||
toggleAll: function(evt) {
|
||||
if (evt) { evt.preventDefault(); };
|
||||
if (evt) { evt.preventDefault(); }
|
||||
|
||||
var aspects = this.$('li:not(:last)')
|
||||
if (this.collection.allSelected()) {
|
||||
this.collection.deselectAll();
|
||||
aspects.each(function(i){
|
||||
$(this).find('.icons-check_yes_ok').removeClass('selected');
|
||||
});
|
||||
} else {
|
||||
this.collection.selectAll();
|
||||
aspects.each(function(i){
|
||||
$(this).find('.icons-check_yes_ok').addClass('selected');
|
||||
});
|
||||
}
|
||||
|
||||
this.toggleSelector();
|
||||
|
|
@ -58,7 +54,19 @@ app.views.AspectsList = app.views.Base.extend({
|
|||
$('.stream_title').text(this.collection.toSentence());
|
||||
},
|
||||
|
||||
updateAspectList: function() {
|
||||
this.collection.each(function(aspect) {
|
||||
var element = this.$("li[data-aspect_id="+aspect.get('id')+"]");
|
||||
if (aspect.get('selected')) {
|
||||
element.find('.entypo.check').addClass('selected');
|
||||
} else {
|
||||
element.find('.entypo.check').removeClass('selected');
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
hideAspectsList: function() {
|
||||
this.$el.empty();
|
||||
},
|
||||
})
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Bookmarklet = Backbone.View.extend({
|
||||
separator: ' - ',
|
||||
|
||||
|
|
@ -28,18 +30,20 @@ app.views.Bookmarklet = Backbone.View.extend({
|
|||
return contents;
|
||||
},
|
||||
|
||||
_postSubmit: function(evt) {
|
||||
_postSubmit: function() {
|
||||
this.$('h4').text(Diaspora.I18n.t('bookmarklet.post_submit'));
|
||||
},
|
||||
|
||||
_postSuccess: function(evt) {
|
||||
_postSuccess: function() {
|
||||
this.$('h4').text(Diaspora.I18n.t('bookmarklet.post_success'));
|
||||
app.publisher.close();
|
||||
this.$("#publisher").addClass("hidden");
|
||||
_.delay(window.close, 2000);
|
||||
},
|
||||
|
||||
_postError: function(evt) {
|
||||
_postError: function() {
|
||||
this.$('h4').text(Diaspora.I18n.t('bookmarklet.post_something'));
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.CommentStream = app.views.Base.extend({
|
||||
|
||||
templateName: "comment-stream",
|
||||
|
|
@ -37,7 +39,7 @@ app.views.CommentStream = app.views.Base.extend({
|
|||
moreCommentsCount : (this.model.interactions.commentsCount() - 3),
|
||||
showExpandCommentsLink : (this.model.interactions.commentsCount() > 3),
|
||||
commentsCount : this.model.interactions.commentsCount()
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
createComment: function(evt) {
|
||||
|
|
@ -55,8 +57,8 @@ app.views.CommentStream = app.views.Base.extend({
|
|||
},
|
||||
|
||||
keyDownOnCommentBox: function(evt) {
|
||||
if(evt.keyCode == 13 && evt.ctrlKey) {
|
||||
this.$("form").submit()
|
||||
if(evt.keyCode === 13 && evt.ctrlKey) {
|
||||
this.$("form").submit();
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
|
@ -64,14 +66,14 @@ app.views.CommentStream = app.views.Base.extend({
|
|||
appendComment: function(comment) {
|
||||
// Set the post as the comment's parent, so we can check
|
||||
// on post ownership in the Comment view.
|
||||
comment.set({parent : this.model.toJSON()})
|
||||
comment.set({parent : this.model.toJSON()});
|
||||
|
||||
this.$(".comments").append(new app.views.Comment({
|
||||
model: comment
|
||||
}).render().el);
|
||||
},
|
||||
|
||||
commentTextareaFocused: function(evt){
|
||||
commentTextareaFocused: function(){
|
||||
this.$("form").removeClass('hidden').addClass("open");
|
||||
},
|
||||
|
||||
|
|
@ -81,18 +83,18 @@ app.views.CommentStream = app.views.Base.extend({
|
|||
|
||||
expandComments: function(evt){
|
||||
if(evt){ evt.preventDefault(); }
|
||||
|
||||
self = this;
|
||||
var self = this;
|
||||
|
||||
this.model.comments.fetch({
|
||||
success : function(resp){
|
||||
self.model.set({
|
||||
comments : resp.models,
|
||||
all_comments_loaded : true
|
||||
})
|
||||
});
|
||||
|
||||
self.model.trigger("commentsExpanded", self)
|
||||
self.model.trigger("commentsExpanded", self);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
//= require ./content_view
|
||||
app.views.Comment = app.views.Content.extend({
|
||||
templateName: "comment",
|
||||
|
|
@ -11,27 +13,27 @@ app.views.Comment = app.views.Content.extend({
|
|||
},
|
||||
|
||||
initialize : function(options){
|
||||
this.templateName = options.templateName || this.templateName
|
||||
this.model.on("change", this.render, this)
|
||||
this.templateName = options.templateName || this.templateName;
|
||||
this.model.on("change", this.render, this);
|
||||
},
|
||||
|
||||
presenter : function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
canRemove: this.canRemove(),
|
||||
text : app.helpers.textFormatter(this.model.get("text"), this.model)
|
||||
})
|
||||
text : app.helpers.textFormatter(this.model.get("text"))
|
||||
});
|
||||
},
|
||||
|
||||
ownComment : function() {
|
||||
return app.currentUser.authenticated() && this.model.get("author").diaspora_id == app.currentUser.get("diaspora_id")
|
||||
return app.currentUser.authenticated() && this.model.get("author").diaspora_id === app.currentUser.get("diaspora_id");
|
||||
},
|
||||
|
||||
postOwner : function() {
|
||||
return app.currentUser.authenticated() && this.model.get("parent").author.diaspora_id == app.currentUser.get("diaspora_id")
|
||||
return app.currentUser.authenticated() && this.model.get("parent").author.diaspora_id === app.currentUser.get("diaspora_id");
|
||||
},
|
||||
|
||||
canRemove : function() {
|
||||
return app.currentUser.authenticated() && (this.ownComment() || this.postOwner())
|
||||
return app.currentUser.authenticated() && (this.ownComment() || this.postOwner());
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -39,3 +41,4 @@ app.views.ExpandedComment = app.views.Comment.extend({
|
|||
postRenderTemplate : function(){
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
77
app/assets/javascripts/app/views/contact_stream_view.js
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.ContactStream = Backbone.View.extend({
|
||||
initialize: function() {
|
||||
this.itemCount = 0;
|
||||
this.perPage = 25;
|
||||
this.query = '';
|
||||
this.resultList = this.collection.toArray();
|
||||
var throttledScroll = _.throttle(_.bind(this.infScroll, this), 200);
|
||||
$(window).scroll(throttledScroll);
|
||||
this.on('renderContacts', this.renderContacts, this);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if( _.isEmpty(this.resultList) ) {
|
||||
var content = document.createDocumentFragment();
|
||||
content = '<div id="no_contacts" class="well">' +
|
||||
' <h4>' +
|
||||
Diaspora.I18n.t('contacts.search_no_results') +
|
||||
' </h4>' +
|
||||
'</div>';
|
||||
this.$el.html(content);
|
||||
} else {
|
||||
this.$el.html('');
|
||||
this.renderContacts();
|
||||
}
|
||||
},
|
||||
|
||||
renderContacts: function() {
|
||||
this.$el.addClass("loading");
|
||||
var content = document.createDocumentFragment();
|
||||
_.rest(_.first(this.resultList , this.itemCount + this.perPage), this.itemCount).forEach( function(item) {
|
||||
var view = new app.views.Contact({model: item});
|
||||
content.appendChild(view.render().el);
|
||||
});
|
||||
|
||||
var size = _.size(this.resultList);
|
||||
if( this.itemCount + this.perPage >= size ){
|
||||
this.itemCount = size;
|
||||
this.off('renderContacts');
|
||||
} else {
|
||||
this.itemCount += this.perPage;
|
||||
}
|
||||
this.$el.append(content);
|
||||
this.$el.removeClass("loading");
|
||||
},
|
||||
|
||||
search: function(query) {
|
||||
query = query.trim();
|
||||
if( query || this.query ) {
|
||||
this.off('renderContacts');
|
||||
this.on('renderContacts', this.renderContacts, this);
|
||||
this.itemCount = 0;
|
||||
if( query ) {
|
||||
this.query = query;
|
||||
var regex = new RegExp(query,'i');
|
||||
this.resultList = this.collection.filter(function(contact) {
|
||||
return regex.test(contact.get('person').name) ||
|
||||
regex.test(contact.get('person').diaspora_id);
|
||||
});
|
||||
} else {
|
||||
this.resultList = this.collection.toArray();
|
||||
this.query = '';
|
||||
}
|
||||
this.render();
|
||||
}
|
||||
},
|
||||
|
||||
infScroll: function() {
|
||||
if( this.$el.hasClass('loading') ) return;
|
||||
|
||||
var distanceTop = $(window).height() + $(window).scrollTop(),
|
||||
distanceBottom = $(document).height() - distanceTop;
|
||||
if(distanceBottom < 300) this.trigger('renderContacts');
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
71
app/assets/javascripts/app/views/contact_view.js
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Contact = app.views.Base.extend({
|
||||
templateName: 'contact',
|
||||
|
||||
events: {
|
||||
"click .contact_add-to-aspect" : "addContactToAspect",
|
||||
"click .contact_remove-from-aspect" : "removeContactFromAspect"
|
||||
},
|
||||
|
||||
tooltipSelector: '.contact_add-to-aspect, .contact_remove-from-aspect',
|
||||
|
||||
presenter: function() {
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
person_id : this.model.get('person_id'),
|
||||
person : this.model.get('person'),
|
||||
in_aspect: (app.aspect && this.model.inAspect(app.aspect.get('id'))) ? 'in_aspect' : '',
|
||||
});
|
||||
},
|
||||
|
||||
postRenderTemplate: function() {
|
||||
var self = this;
|
||||
var dropdownEl = this.$('.aspect_membership_dropdown.placeholder');
|
||||
if( dropdownEl.length === 0 ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO render me client side!!!
|
||||
var href = this.model.person.url() + '/aspect_membership_button?size=small';
|
||||
|
||||
$.get(href, function(resp) {
|
||||
dropdownEl.html(resp);
|
||||
new app.views.AspectMembership({el: $('.aspect_dropdown',dropdownEl)});
|
||||
|
||||
// UGLY (re-)attach the facebox
|
||||
self.$('a[rel*=facebox]').facebox();
|
||||
});
|
||||
},
|
||||
|
||||
addContactToAspect: function(){
|
||||
var self = this;
|
||||
this.model.aspect_memberships.create({
|
||||
'person_id': this.model.get('person_id'),
|
||||
'aspect_id': app.aspect.get('id')
|
||||
},{
|
||||
success: function(){
|
||||
self.render();
|
||||
},
|
||||
error: function(){
|
||||
var msg = Diaspora.I18n.t('contacts.error_add', { 'name': self.model.get('person').name });
|
||||
Diaspora.page.flashMessages.render({ 'success':false, 'notice':msg });
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
removeContactFromAspect: function(){
|
||||
var self = this;
|
||||
this.model.aspect_memberships
|
||||
.find(function(membership){ return membership.get('aspect').id === app.aspect.id; })
|
||||
.destroy({
|
||||
success: function(){
|
||||
self.render();
|
||||
},
|
||||
error: function(){
|
||||
var msg = Diaspora.I18n.t('contacts.error_remove', { 'name': self.model.get('person').name });
|
||||
Diaspora.page.flashMessages.render({ 'success':false, 'notice':msg });
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Content = app.views.Base.extend({
|
||||
events: {
|
||||
"click .expander": "expandPost"
|
||||
|
|
@ -5,7 +7,7 @@ app.views.Content = app.views.Base.extend({
|
|||
|
||||
presenter : function(){
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
text : app.helpers.textFormatter(this.model.get("text"), this.model),
|
||||
text : app.helpers.textFormatter(this.model.get("text"), this.model.get("mentioned_people")),
|
||||
largePhoto : this.largePhoto(),
|
||||
smallPhotos : this.smallPhotos(),
|
||||
location: this.location()
|
||||
|
|
@ -14,13 +16,13 @@ app.views.Content = app.views.Base.extend({
|
|||
|
||||
|
||||
largePhoto : function() {
|
||||
var photos = this.model.get("photos")
|
||||
if(!photos || photos.length == 0) { return }
|
||||
return photos[0]
|
||||
var photos = this.model.get("photos");
|
||||
if(!photos || photos.length === 0) { return }
|
||||
return photos[0];
|
||||
},
|
||||
|
||||
smallPhotos : function() {
|
||||
var photos = this.model.get("photos")
|
||||
var photos = this.model.get("photos");
|
||||
if(!photos || photos.length < 2) { return }
|
||||
photos.splice(0, 1); // remove first photo as it is already shown as largePhoto
|
||||
return photos;
|
||||
|
|
@ -47,10 +49,10 @@ app.views.Content = app.views.Base.extend({
|
|||
, oembed = elem.find(".oembed")
|
||||
, opengraph = elem.find(".opengraph")
|
||||
, addHeight = 0;
|
||||
if($.trim(oembed.html()) != "") {
|
||||
if($.trim(oembed.html()) !== "") {
|
||||
addHeight += oembed.height();
|
||||
}
|
||||
if($.trim(opengraph.html()) != "") {
|
||||
if($.trim(opengraph.html()) !== "") {
|
||||
addHeight += opengraph.height();
|
||||
}
|
||||
|
||||
|
|
@ -69,7 +71,7 @@ app.views.Content = app.views.Base.extend({
|
|||
},
|
||||
|
||||
postRenderTemplate : function(){
|
||||
_.defer(_.bind(this.collapseOversized, this))
|
||||
_.defer(_.bind(this.collapseOversized, this));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -93,26 +95,55 @@ app.views.OEmbed = app.views.Base.extend({
|
|||
},
|
||||
|
||||
presenter:function () {
|
||||
o_embed_cache = this.model.get("o_embed_cache")
|
||||
var o_embed_cache = this.model.get("o_embed_cache");
|
||||
if(o_embed_cache) {
|
||||
typemodel = { rich: false, photo: false, video: false, link: false }
|
||||
typemodel[o_embed_cache.data.type] = true
|
||||
o_embed_cache.data.types = typemodel
|
||||
var typemodel = { rich: false, photo: false, video: false, link: false };
|
||||
typemodel[o_embed_cache.data.type] = true;
|
||||
o_embed_cache.data.types = typemodel;
|
||||
}
|
||||
return _.extend(this.defaultPresenter(), {
|
||||
o_embed_html : app.helpers.oEmbed.html(o_embed_cache)
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
showOembedContent : function (evt) {
|
||||
if( $(evt.target).is('a') ) return;
|
||||
var clickedThumb = false;
|
||||
if ($(evt.target).hasClass(".thumb")) {
|
||||
clickedThumb = $(evt.target);
|
||||
} else {
|
||||
clickedThumb = $(evt.target).parent(".thumb");
|
||||
}
|
||||
var insertHTML = $(app.helpers.oEmbed.html(this.model.get("o_embed_cache")));
|
||||
var paramSeparator = ( /\?/.test(insertHTML.attr("src")) ) ? "&" : "?";
|
||||
insertHTML.attr("src", insertHTML.attr("src") + paramSeparator + "autoplay=1&wmode=opaque");
|
||||
if (clickedThumb) {
|
||||
insertHTML.attr("width", clickedThumb.width());
|
||||
insertHTML.attr("height", clickedThumb.height());
|
||||
}
|
||||
this.$el.html(insertHTML);
|
||||
}
|
||||
});
|
||||
|
||||
app.views.OpenGraph = app.views.Base.extend({
|
||||
templateName : "opengraph"
|
||||
templateName : "opengraph",
|
||||
|
||||
initialize: function() {
|
||||
this.truncateDescription();
|
||||
},
|
||||
|
||||
truncateDescription: function() {
|
||||
// truncate opengraph description to 250 for stream view
|
||||
if(this.model.has('open_graph_cache')) {
|
||||
var ogdesc = this.model.get('open_graph_cache');
|
||||
ogdesc.description = app.helpers.truncate(ogdesc.description, 250);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
app.views.SPVOpenGraph = app.views.OpenGraph.extend({
|
||||
truncateDescription: function () {
|
||||
// override with nothing
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
31
app/assets/javascripts/app/views/conversations_form_view.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.ConversationsForm = Backbone.View.extend({
|
||||
|
||||
initialize: function(opts) {
|
||||
this.contacts = _.has(opts, 'contacts') ? opts.contacts : null;
|
||||
this.prefill = [];
|
||||
if (_.has(opts, 'prefillName') && _.has(opts, 'prefillValue')) {
|
||||
this.prefill = [{name : opts.prefillName,
|
||||
value : opts.prefillValue}];
|
||||
}
|
||||
this.autocompleteInput = $("#contact_autocomplete");
|
||||
this.prepareAutocomplete(this.contacts);
|
||||
},
|
||||
|
||||
prepareAutocomplete: function(data){
|
||||
this.autocompleteInput.autoSuggest(data, {
|
||||
selectedItemProp: "name",
|
||||
searchObjProps: "name",
|
||||
asHtmlID: "contact_ids",
|
||||
retrieveLimit: 10,
|
||||
minChars: 1,
|
||||
keyDelay: 0,
|
||||
startText: '',
|
||||
emptyText: Diaspora.I18n.t('no_results'),
|
||||
preFill: this.prefill
|
||||
}).focus();
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
49
app/assets/javascripts/app/views/conversations_view.js
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Conversations = Backbone.View.extend({
|
||||
|
||||
el: "#conversations_container",
|
||||
|
||||
events: {
|
||||
"conversation:loaded" : "setupConversation"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
if($('#conversation_new:visible').length > 0) {
|
||||
new app.views.ConversationsForm({contacts: gon.contacts});
|
||||
}
|
||||
this.setupConversation();
|
||||
},
|
||||
|
||||
setupConversation: function() {
|
||||
app.helpers.timeago($(this.el));
|
||||
$('.control-icons a').tooltip({placement: 'bottom'});
|
||||
|
||||
var conv = $('.conversation-wrapper .stream_element.selected'),
|
||||
cBadge = $('#conversations_badge .badge_count');
|
||||
|
||||
if(conv.hasClass('unread') ){
|
||||
var unreadCount = parseInt(conv.find('.unread_message_count').text(), 10);
|
||||
|
||||
if(cBadge.text() !== '') {
|
||||
cBadge.text().replace(/\d+/, function(num){
|
||||
num = parseInt(num, 10) - unreadCount;
|
||||
if(num > 0) {
|
||||
cBadge.text(num);
|
||||
} else {
|
||||
cBadge.text(0).addClass('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
conv.removeClass('unread');
|
||||
conv.find('.unread_message_count').remove();
|
||||
|
||||
var pos = $('#first_unread').offset().top - 50;
|
||||
$("html").animate({scrollTop:pos});
|
||||
} else {
|
||||
$("html").animate({scrollTop:0});
|
||||
}
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.FaqQuestionView = app.views.Base.extend({
|
||||
|
||||
templateName: "faq_question",
|
||||
|
|
@ -26,12 +28,14 @@ app.views.FaqQuestionView = app.views.Base.extend({
|
|||
},
|
||||
|
||||
toggled: function(e) {
|
||||
el = $(e.target);
|
||||
parent = el.parents('.question');
|
||||
var el = $(e.target);
|
||||
var parent = el.parents('.question');
|
||||
|
||||
parent.children('.answer').toggle();
|
||||
parent.toggleClass('opened').toggleClass('collapsed');
|
||||
|
||||
e.preventDefault();
|
||||
},
|
||||
});
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
//=require "./feedback_view"
|
||||
app.views.FeedbackActions = app.views.Feedback.extend({
|
||||
id : "user-controls",
|
||||
templateName : "feedback-actions",
|
||||
events: {},
|
||||
initialize: function(){}
|
||||
});
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Feedback = app.views.Base.extend({
|
||||
templateName: "feedback",
|
||||
|
||||
|
|
@ -6,18 +8,21 @@ app.views.Feedback = app.views.Base.extend({
|
|||
events: {
|
||||
"click .like" : "toggleLike",
|
||||
"click .reshare" : "resharePost",
|
||||
"click .post_report" : "report"
|
||||
|
||||
"click .post_report" : "report",
|
||||
"click .block_user" : "blockUser",
|
||||
"click .hide_post" : "hidePost",
|
||||
},
|
||||
|
||||
tooltipSelector : ".label",
|
||||
|
||||
initialize : function() {
|
||||
this.model.interactions.on('change', this.render, this);
|
||||
this.initViews && this.initViews() // I don't know why this was failing with $.noop... :(
|
||||
this.initViews && this.initViews(); // I don't know why this was failing with $.noop... :(
|
||||
},
|
||||
|
||||
presenter : function() {
|
||||
var interactions = this.model.interactions
|
||||
var interactions = this.model.interactions;
|
||||
|
||||
return _.extend(this.defaultPresenter(),{
|
||||
commentsCount : interactions.commentsCount(),
|
||||
|
|
@ -26,7 +31,7 @@ app.views.Feedback = app.views.Base.extend({
|
|||
userCanReshare : interactions.userCanReshare(),
|
||||
userLike : interactions.userLike(),
|
||||
userReshare : interactions.userReshare()
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
toggleLike: function(evt) {
|
||||
|
|
@ -38,5 +43,45 @@ app.views.Feedback = app.views.Base.extend({
|
|||
if(evt) { evt.preventDefault(); }
|
||||
if(!window.confirm(Diaspora.I18n.t("reshares.post", {name: this.model.reshareAuthor().name}))) { return }
|
||||
this.model.interactions.reshare();
|
||||
}
|
||||
},
|
||||
|
||||
blockUser: function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
if(!confirm(Diaspora.I18n.t('ignore_user'))) { return; }
|
||||
|
||||
this.model.blockAuthor()
|
||||
.done(function() {
|
||||
// return to stream
|
||||
document.location.href = "/stream";
|
||||
})
|
||||
.fail(function() {
|
||||
Diaspora.page.flashMessages.render({
|
||||
success: false,
|
||||
notice: Diaspora.I18n.t('hide_post_failed')
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
hidePost : function(evt) {
|
||||
if(evt) { evt.preventDefault(); }
|
||||
if(!confirm(Diaspora.I18n.t('hide_post'))) { return; }
|
||||
|
||||
$.ajax({
|
||||
url : "/share_visibilities/42",
|
||||
type : "PUT",
|
||||
data : {
|
||||
post_id : this.model.id
|
||||
}
|
||||
}).done(function() {
|
||||
// return to stream
|
||||
document.location.href = "/stream";
|
||||
})
|
||||
.fail(function() {
|
||||
Diaspora.page.flashMessages.render({
|
||||
success: false,
|
||||
notice: Diaspora.I18n.t('ignore_post_failed')
|
||||
});
|
||||
});
|
||||
},
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,45 +1,53 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Header = app.views.Base.extend({
|
||||
|
||||
templateName : "header",
|
||||
templateName: "header",
|
||||
|
||||
className : "dark-header",
|
||||
className: "dark-header",
|
||||
|
||||
events : {
|
||||
"click ul.dropdown li:first-child" : "toggleDropdown",
|
||||
events: {
|
||||
"click ul.dropdown li:first-child": "toggleUserDropdown",
|
||||
"focusin #q": "toggleSearchActive",
|
||||
"focusout #q": "toggleSearchActive"
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
$(document.body).click($.proxy(this.hideDropdown, this));
|
||||
initialize: function(){
|
||||
$(document.body).click($.proxy(this.hideUserDropdown, this));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
menuElement : function() {
|
||||
return this.$("ul.dropdown");
|
||||
postRenderTemplate: function(){
|
||||
new app.views.Notifications({ el: '#notification_dropdown' });
|
||||
new app.views.NotificationDropdown({ el: '#notification_badge' });
|
||||
new app.views.Search({ el: '#header-search-form' });
|
||||
},
|
||||
|
||||
toggleDropdown : function(evt) {
|
||||
menuElement: function(){ return this.$("ul.dropdown"); },
|
||||
|
||||
toggleUserDropdown: function(evt){
|
||||
if(evt){ evt.preventDefault(); }
|
||||
|
||||
this.menuElement().toggleClass("active");
|
||||
|
||||
if($.browser.msie) {
|
||||
if($.browser.msie){
|
||||
this.$("header").toggleClass('ie-user-menu-active');
|
||||
}
|
||||
},
|
||||
|
||||
hideDropdown : function(evt) {
|
||||
if(this.menuElement().hasClass("active") && !$(evt.target).parents("#user_menu").length) {
|
||||
hideUserDropdown: function(evt){
|
||||
if(this.menuElement().hasClass("active") && !$(evt.target).parents("#user_menu").length){
|
||||
this.menuElement().removeClass("active");
|
||||
}
|
||||
},
|
||||
|
||||
toggleSearchActive: function(ev) {
|
||||
toggleSearchActive: function(ev){
|
||||
// jQuery produces two events for focus/blur (for bubbling)
|
||||
// don't rely on which event arrives first, by allowing for both variants
|
||||
var is_active = (_.indexOf(['focus','focusin'], ev.type) != -1);
|
||||
var is_active = (_.indexOf(['focus','focusin'], ev.type) !== -1);
|
||||
$(ev.target).toggleClass('active', is_active);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.HelpSectionView = app.views.StaticContentView.extend({
|
||||
|
||||
events: {
|
||||
|
|
@ -24,8 +26,8 @@ app.views.HelpSectionView = app.views.StaticContentView.extend({
|
|||
},
|
||||
|
||||
toggled: function(e) {
|
||||
el = $(e.target);
|
||||
parent = el.parents('.question');
|
||||
var el = $(e.target);
|
||||
var parent = el.parents('.question');
|
||||
|
||||
parent.children('.answer.hideable').toggle();
|
||||
parent.toggleClass('opened').toggleClass('collapsed');
|
||||
|
|
@ -52,3 +54,5 @@ app.views.HelpSectionView = app.views.StaticContentView.extend({
|
|||
},
|
||||
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Help = app.views.StaticContentView.extend({
|
||||
templateName : "help",
|
||||
|
||||
|
|
@ -6,23 +8,39 @@ app.views.Help = app.views.StaticContentView.extend({
|
|||
"click .faq-link-getting-help" : "gettingHelp",
|
||||
"click .faq-link-sharing" : "sharing",
|
||||
"click .faq-link-posts-and-posting" : "postsAndPosting",
|
||||
"click .faq-link-tags": "tags",
|
||||
"click .faq-link-keyboard-shortcuts" : "keyboardShortcuts",
|
||||
"click .faq-link-chat" : "chat"
|
||||
},
|
||||
|
||||
initialize : function(options) {
|
||||
initialize : function() {
|
||||
this.GETTING_HELP_SUBS = {
|
||||
getting_started_a: { tutorial_series: this.linkHtml("http://diasporafoundation.org/getting_started/sign_up", Diaspora.I18n.t( 'getting_started_tutorial' )) },
|
||||
get_support_a_website: { link: this.linkHtml("https://diasporafoundation.org/", Diaspora.I18n.t( 'foundation_website' ))},
|
||||
get_support_a_tutorials: { tutorials: this.linkHtml("https://diasporafoundation.org/tutorials", Diaspora.I18n.t( 'tutorials' ))},
|
||||
get_support_a_wiki: { link: this.linkHtml("https://wiki.diasporafoundation.org/Special:Search", Diaspora.I18n.t( 'wiki' ))},
|
||||
get_support_a_irc: { irc: this.linkHtml("https://wiki.diasporafoundation.org/How_We_Communicate#IRC", Diaspora.I18n.t( 'irc' ))},
|
||||
get_support_a_hashtag: { question: this.linkHtml("/tags/question", "#question")},
|
||||
get_support_a_faq: { faq: this.linkHtml("https://wiki.diasporafoundation.org/FAQ_for_users", Diaspora.I18n.t( 'faq' ))},
|
||||
get_support_a_hashtag: { question: this.linkHtml("/tags/question", "#question")}
|
||||
};
|
||||
|
||||
this.POSTS_AND_POSTING_SUBS = {
|
||||
format_text_a: {
|
||||
markdown: this.linkHtml("http://diasporafoundation.org/formatting", Diaspora.I18n.t( 'markdown' )),
|
||||
here: this.linkHtml("http://daringfireball.net/projects/markdown/syntax", Diaspora.I18n.t( 'here' )),
|
||||
here: this.linkHtml("http://daringfireball.net/projects/markdown/syntax", Diaspora.I18n.t( 'here' ))
|
||||
}
|
||||
};
|
||||
|
||||
this.TAGS_SUBS = {
|
||||
filter_tags_a: {
|
||||
third_party_tools: this.linkHtml("https://wiki.diasporafoundation.org/Tools_to_use_with_Diaspora", Diaspora.I18n.t( 'third_party_tools' ))
|
||||
}
|
||||
};
|
||||
|
||||
this.CHAT_SUBS = {
|
||||
add_contact_roster_a: {
|
||||
toggle_privilege: this.getChatIcons(),
|
||||
contacts_page: this.linkHtml(Routes.contacts_path(), Diaspora.I18n.t('chat.contacts_page'))
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -43,19 +61,24 @@ app.views.Help = app.views.StaticContentView.extend({
|
|||
title_tags: Diaspora.I18n.t( 'tags.title' ),
|
||||
title_keyboard_shortcuts: Diaspora.I18n.t( 'keyboard_shortcuts.title' ),
|
||||
title_miscellaneous: Diaspora.I18n.t( 'miscellaneous.title' ),
|
||||
}
|
||||
title_chat: Diaspora.I18n.t( 'chat.title' ),
|
||||
chat_enabled: this.chatEnabled()
|
||||
};
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
render: function(){
|
||||
var section = app.views.Base.prototype.render.apply(this, arguments);
|
||||
render: function(section){
|
||||
var html = app.views.Base.prototype.render.apply(this, arguments);
|
||||
|
||||
// After render actions
|
||||
this.resetMenu(true);
|
||||
this.renderStaticSection("getting_help", "faq_getting_help", this.GETTING_HELP_SUBS);
|
||||
|
||||
return section;
|
||||
var elTarget = this.findSection(section);
|
||||
if(elTarget !== null){ $(elTarget).click(); }
|
||||
|
||||
return html;
|
||||
},
|
||||
|
||||
showItems: function(el) {
|
||||
|
|
@ -98,8 +121,12 @@ app.views.Help = app.views.StaticContentView.extend({
|
|||
|
||||
menuClicked: function(e) {
|
||||
this.resetMenu();
|
||||
|
||||
$(e.target).hide();
|
||||
$(e.target).next().show();
|
||||
|
||||
var data = $(e.target).data('section');
|
||||
app.router.navigate('help/' + data);
|
||||
},
|
||||
|
||||
clearItems: function() {
|
||||
|
|
@ -115,8 +142,8 @@ app.views.Help = app.views.StaticContentView.extend({
|
|||
|
||||
renderStaticSection: function(section, template, subs) {
|
||||
this.clearItems();
|
||||
data = $.extend(Diaspora.I18n.resolve(section), { className: section });
|
||||
help_section = new app.views.HelpSectionView({
|
||||
var data = $.extend(Diaspora.I18n.resolve(section), { className: section });
|
||||
var help_section = new app.views.HelpSectionView({
|
||||
template: template,
|
||||
data: data,
|
||||
subs: subs
|
||||
|
|
@ -124,6 +151,18 @@ app.views.Help = app.views.StaticContentView.extend({
|
|||
this.$('#faq').append(help_section.render().el);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns The section title whose data-section property equals the given query
|
||||
* Returns null if nothing found
|
||||
* @param data Value for the data-section to find
|
||||
* @returns {jQuery}
|
||||
*/
|
||||
findSection: function(data){
|
||||
var res = this.$('a[data-section=' + data + ']');
|
||||
if(res.length === 0){ return null; }
|
||||
return res;
|
||||
},
|
||||
|
||||
gettingHelp: function(e) {
|
||||
this.renderStaticSection("getting_help", "faq_getting_help", this.GETTING_HELP_SUBS);
|
||||
this.menuClicked(e);
|
||||
|
|
@ -145,6 +184,13 @@ app.views.Help = app.views.StaticContentView.extend({
|
|||
e.preventDefault();
|
||||
},
|
||||
|
||||
tags: function(e) {
|
||||
this.renderStaticSection("tags", "faq_tags", this.TAGS_SUBS);
|
||||
this.menuClicked(e);
|
||||
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
keyboardShortcuts: function(e) {
|
||||
this.renderStaticSection("keyboard_shortcuts", "faq_keyboard_shortcuts", {});
|
||||
this.menuClicked(e);
|
||||
|
|
@ -152,7 +198,27 @@ app.views.Help = app.views.StaticContentView.extend({
|
|||
e.preventDefault();
|
||||
},
|
||||
|
||||
chat: function(e){
|
||||
this.renderStaticSection("chat", "faq_chat", this.CHAT_SUBS);
|
||||
this.menuClicked(e);
|
||||
|
||||
e.preventDefault();
|
||||
},
|
||||
|
||||
linkHtml: function(url, text) {
|
||||
return "<a href=\"" + url + "\" target=\"_blank\">" + text + "</a>";
|
||||
},
|
||||
|
||||
chatEnabled: function(){
|
||||
return gon.chatEnabled;
|
||||
},
|
||||
|
||||
getChatIcons: function(){
|
||||
return '<div class="help-chat-icons">' +
|
||||
' <i class="entypo lock-open"></i>' +
|
||||
' <i class="entypo chat"></i>' +
|
||||
' <i class="entypo trash"></i>' +
|
||||
'</div>';
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Hovercard = app.views.Base.extend({
|
||||
templateName: 'hovercard',
|
||||
|
|
@ -14,8 +15,8 @@ app.views.Hovercard = app.views.Base.extend({
|
|||
.on('mouseenter', '.hovercardable', _.bind(this._mouseenterHandler, this))
|
||||
.on('mouseleave', '.hovercardable', _.bind(this._mouseleaveHandler, this));
|
||||
|
||||
this.show_me = false;
|
||||
this.parent = null; // current 'hovercarable' element that caused HC to appear
|
||||
this.showMe = false;
|
||||
this.parent = null; // current 'hovercardable' element that caused HC to appear
|
||||
|
||||
// cache some element references
|
||||
this.avatar = this.$('.avatar');
|
||||
|
|
@ -28,7 +29,7 @@ app.views.Hovercard = app.views.Base.extend({
|
|||
},
|
||||
|
||||
postRenderTemplate: function() {
|
||||
this.$el.appendTo($('body'))
|
||||
this.$el.appendTo($('body'));
|
||||
},
|
||||
|
||||
deactivate: function() {
|
||||
|
|
@ -40,7 +41,7 @@ app.views.Hovercard = app.views.Base.extend({
|
|||
},
|
||||
|
||||
_mouseenterHandler: function(event) {
|
||||
if( this.active == false ||
|
||||
if( this.active === false ||
|
||||
$.contains(this.el, event.target) ) { return false; }
|
||||
|
||||
var el = $(event.target);
|
||||
|
|
@ -48,28 +49,31 @@ app.views.Hovercard = app.views.Base.extend({
|
|||
el = el.parents('a');
|
||||
}
|
||||
|
||||
if( el.attr('href').indexOf('/people') == -1 ) {
|
||||
if( el.attr('href').indexOf('/people') === -1 ) {
|
||||
// can't fetch data from that URL, aborting
|
||||
return false;
|
||||
}
|
||||
|
||||
this.show_me = true;
|
||||
this.showMe = true;
|
||||
this.showHovercardOn(el);
|
||||
return false;
|
||||
},
|
||||
|
||||
_mouseleaveHandler: function(event) {
|
||||
if( this.active == false ||
|
||||
$.contains(this.el, event.relatedTarget) ) { return false; }
|
||||
this.showMe = false;
|
||||
if( this.active === false ||
|
||||
$.contains(this.el, event.relatedTarget) ) { return false; }
|
||||
|
||||
if( this.mouseIsOverElement(this.parent, event) ||
|
||||
this.mouseIsOverElement(this.$el, event) ) { return false; }
|
||||
|
||||
this.show_me = false;
|
||||
if( this.$el.is(':visible') ) {
|
||||
this.$el.fadeOut('fast');
|
||||
} else {
|
||||
this.$el.hide();
|
||||
}
|
||||
|
||||
this.dropdown_container.empty();
|
||||
this.dropdown_container.unbind().empty();
|
||||
return false;
|
||||
},
|
||||
|
||||
|
|
@ -77,7 +81,7 @@ app.views.Hovercard = app.views.Base.extend({
|
|||
var el = $(element);
|
||||
var hc = this.$el;
|
||||
|
||||
if( !this.show_me ) {
|
||||
if( !this.showMe ) {
|
||||
// mouse has left element
|
||||
return;
|
||||
}
|
||||
|
|
@ -94,11 +98,15 @@ app.views.Hovercard = app.views.Base.extend({
|
|||
|
||||
var self = this;
|
||||
$.get(href, function(person){
|
||||
if( !person || person.length == 0 ) {
|
||||
if( !person || person.length === 0 ) {
|
||||
throw new Error("received data is not a person object");
|
||||
}
|
||||
|
||||
self._populateHovercardWith(person);
|
||||
if( !self.showMe ) {
|
||||
// mouse has left element
|
||||
return;
|
||||
}
|
||||
self.$el.fadeIn('fast');
|
||||
});
|
||||
},
|
||||
|
|
@ -119,15 +127,13 @@ app.views.Hovercard = app.views.Base.extend({
|
|||
})) );
|
||||
|
||||
// set aspect dropdown
|
||||
// TODO render me client side!!!
|
||||
var href = this.href();
|
||||
href += "/aspect_membership_button";
|
||||
if(gon.bootstrap == true){
|
||||
href += "?bootstrap=true";
|
||||
}
|
||||
$.get(href, function(response) {
|
||||
self.dropdown_container.html(response);
|
||||
});
|
||||
var aspect_membership = new app.views.AspectMembership({el: self.dropdown_container});
|
||||
new app.views.AspectMembership({el: self.dropdown_container});
|
||||
},
|
||||
|
||||
_positionHovercard: function() {
|
||||
|
|
@ -138,5 +144,14 @@ app.views.Hovercard = app.views.Base.extend({
|
|||
top: p_pos.top + p_height - 25,
|
||||
left: p_pos.left
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
mouseIsOverElement: function(element, event) {
|
||||
var elPos = element.offset();
|
||||
return event.pageX >= elPos.left &&
|
||||
event.pageX <= elPos.left + element.width() &&
|
||||
event.pageY >= elPos.top &&
|
||||
event.pageY <= elPos.top + element.height();
|
||||
},
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
// Abstract Infinite Scroll View Super Class
|
||||
// Requires:
|
||||
// a stream model, assigned to this.stream
|
||||
|
|
@ -32,7 +34,7 @@ app.views.InfScroll = app.views.Base.extend({
|
|||
|
||||
createPostView : function(post){
|
||||
var postView = new this.postClass({ model: post, stream: this.stream });
|
||||
if (this.collection.at(0).id == post.id) {
|
||||
if (this.collection.at(0).id === post.id) {
|
||||
// post is first in collection - insert view at top of the list
|
||||
this.postViews.unshift(postView);
|
||||
} else {
|
||||
|
|
@ -44,7 +46,7 @@ app.views.InfScroll = app.views.Base.extend({
|
|||
// called for every item inserted in this.collection
|
||||
addPostView : function(post) {
|
||||
var el = this.createPostView(post).render().el;
|
||||
if (this.collection.at(0).id == post.id) {
|
||||
if (this.collection.at(0).id === post.id) {
|
||||
this.prependedPosts.insertBefore(el, this.prependedPosts.firstChild);
|
||||
} else {
|
||||
this.appendedPosts.appendChild(el);
|
||||
|
|
@ -56,7 +58,7 @@ app.views.InfScroll = app.views.Base.extend({
|
|||
},
|
||||
|
||||
renderTemplate : function(){
|
||||
this.renderInitialPosts()
|
||||
this.renderInitialPosts();
|
||||
},
|
||||
|
||||
renderInitialPosts : function(){
|
||||
|
|
@ -64,7 +66,7 @@ app.views.InfScroll = app.views.Base.extend({
|
|||
var els = document.createDocumentFragment();
|
||||
this.stream.items.each(_.bind(function(post){
|
||||
els.appendChild(this.createPostView(post).render().el);
|
||||
}, this))
|
||||
}, this));
|
||||
this.$el.html(els);
|
||||
},
|
||||
|
||||
|
|
@ -76,7 +78,7 @@ app.views.InfScroll = app.views.Base.extend({
|
|||
},
|
||||
|
||||
showLoader: function(){
|
||||
$("#paginate .loader").removeClass("hidden")
|
||||
$("#paginate .loader").removeClass("hidden");
|
||||
},
|
||||
|
||||
finishedAdding: function() {
|
||||
|
|
@ -105,3 +107,4 @@ app.views.InfScroll = app.views.Base.extend({
|
|||
}
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.LikesInfo = app.views.Base.extend({
|
||||
|
||||
templateName : "likes-info",
|
||||
|
|
@ -17,11 +19,12 @@ app.views.LikesInfo = app.views.Base.extend({
|
|||
likes : this.model.interactions.likes.toJSON(),
|
||||
likesCount : this.model.interactions.likesCount(),
|
||||
likes_fetched : this.model.interactions.get("fetched"),
|
||||
})
|
||||
});
|
||||
},
|
||||
|
||||
showAvatars : function(evt){
|
||||
if(evt) { evt.preventDefault() }
|
||||
this.model.interactions.fetch()
|
||||
this.model.interactions.fetch();
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.LocationStream = app.views.Content.extend({
|
||||
templateName: "status-message-location"
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Location = Backbone.View.extend({
|
||||
|
||||
el: "#location",
|
||||
|
|
@ -8,18 +10,18 @@ app.views.Location = Backbone.View.extend({
|
|||
},
|
||||
|
||||
render: function(){
|
||||
$(this.el).append('<img alt="delete location" src="/assets/ajax-loader.gif">');
|
||||
$(this.el).append('<img alt="ajax-loader" src="'+ImagePaths.get('ajax-loader.gif')+'">');
|
||||
},
|
||||
|
||||
getLocation: function(e){
|
||||
element = this.el;
|
||||
getLocation: function(){
|
||||
var element = this.el;
|
||||
|
||||
locator = new OSM.Locator();
|
||||
var locator = new OSM.Locator();
|
||||
locator.getAddress(function(address, latlng){
|
||||
$(element).html('<input id="location_address" type="text" class="input-block-level" value="' + address + '"/>');
|
||||
$('#location_coords').val(latlng.latitude + "," + latlng.longitude);
|
||||
$(element).append('<a id="hide_location"><img alt="delete location" src="/assets/deletelabel.png"></a>');
|
||||
});
|
||||
},
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
118
app/assets/javascripts/app/views/notification_dropdown_view.js
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.NotificationDropdown = app.views.Base.extend({
|
||||
events:{
|
||||
"click #notifications-badge": "toggleDropdown"
|
||||
},
|
||||
|
||||
initialize: function(){
|
||||
$(document.body).click($.proxy(this.hideDropdown, this));
|
||||
|
||||
this.notifications = [];
|
||||
this.perPage = 5;
|
||||
this.hasMoreNotifs = true;
|
||||
this.badge = this.$el;
|
||||
this.dropdown = $('#notification_dropdown');
|
||||
this.dropdownNotifications = this.dropdown.find('.notifications');
|
||||
this.ajaxLoader = this.dropdown.find('.ajax_loader');
|
||||
},
|
||||
|
||||
toggleDropdown: function(evt){
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
if(this.dropdownShowing()){ this.hideDropdown(evt); }
|
||||
else{ this.showDropdown(); }
|
||||
},
|
||||
|
||||
dropdownShowing: function(){
|
||||
return this.dropdown.css('display') === 'block';
|
||||
},
|
||||
|
||||
showDropdown: function(){
|
||||
this.resetParams();
|
||||
this.ajaxLoader.show();
|
||||
this.badge.addClass('active');
|
||||
this.dropdown.css('display', 'block');
|
||||
this.dropdownNotifications.addClass('loading');
|
||||
this.getNotifications();
|
||||
},
|
||||
|
||||
hideDropdown: function(evt){
|
||||
var inDropdown = $(evt.target).parents().is(this.dropdown);
|
||||
var inHovercard = $.contains(app.hovercard.el, evt.target);
|
||||
if(!inDropdown && !inHovercard && this.dropdownShowing()){
|
||||
this.badge.removeClass('active');
|
||||
this.dropdown.css('display', 'none');
|
||||
this.dropdownNotifications.perfectScrollbar('destroy');
|
||||
}
|
||||
},
|
||||
|
||||
dropdownScroll: function(){
|
||||
var isLoading = ($('.loading').length === 1);
|
||||
if (this.isBottom() && this.hasMoreNotifs && !isLoading){
|
||||
this.dropdownNotifications.addClass('loading');
|
||||
this.getNotifications();
|
||||
}
|
||||
},
|
||||
|
||||
getParams: function(){
|
||||
if(this.notifications.length === 0){ return{ per_page: 10, page: 1 }; }
|
||||
else{ return{ per_page: this.perPage, page: this.nextPage }; }
|
||||
},
|
||||
|
||||
resetParams: function(){
|
||||
this.notifications.length = 0;
|
||||
this.hasMoreNotifs = true;
|
||||
delete this.nextPage;
|
||||
},
|
||||
|
||||
isBottom: function(){
|
||||
var bottom = this.dropdownNotifications.prop('scrollHeight') - this.dropdownNotifications.height();
|
||||
var currentPosition = this.dropdownNotifications.scrollTop();
|
||||
return currentPosition + 50 >= bottom;
|
||||
},
|
||||
|
||||
getNotifications: function(){
|
||||
var self = this;
|
||||
$.getJSON(Routes.notifications_path(this.getParams()), function(notifications){
|
||||
$.each(notifications, function(){ self.notifications.push(this); });
|
||||
self.hasMoreNotifs = notifications.length >= self.perPage;
|
||||
if(self.nextPage){ self.nextPage++; }
|
||||
else { self.nextPage = 3; }
|
||||
self.renderNotifications();
|
||||
});
|
||||
},
|
||||
|
||||
hideAjaxLoader: function(){
|
||||
var self = this;
|
||||
this.ajaxLoader.find('img').fadeTo(200, 0, function(){
|
||||
self.ajaxLoader.hide(300, function(){
|
||||
self.ajaxLoader.find('img').css('opacity', 1);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
renderNotifications: function(){
|
||||
var self = this;
|
||||
this.dropdownNotifications.find('.media.stream_element').remove();
|
||||
$.each(self.notifications, function(index, notifications){
|
||||
$.each(notifications, function(index, notification){
|
||||
if($.inArray(notification, notifications) === -1){
|
||||
var node = self.dropdownNotifications.append(notification.note_html);
|
||||
$(node).find('.unread-toggle .entypo').tooltip('destroy').tooltip();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this.hideAjaxLoader();
|
||||
|
||||
app.helpers.timeago(this.dropdownNotifications);
|
||||
|
||||
this.dropdownNotifications.perfectScrollbar('destroy').perfectScrollbar();
|
||||
this.dropdownNotifications.removeClass('loading');
|
||||
this.dropdownNotifications.scroll(function(){
|
||||
self.dropdownScroll();
|
||||
});
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
@ -1,40 +1,35 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Notifications = Backbone.View.extend({
|
||||
|
||||
events: {
|
||||
"click .unread-toggle" : "toggleUnread"
|
||||
"click .unread-toggle" : "toggleUnread",
|
||||
"click #mark_all_read_link": "markAllRead"
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
Diaspora.page.header.notifications.setUpNotificationPage(this);
|
||||
$(".unread-toggle .entypo").tooltip();
|
||||
app.helpers.timeago($(document));
|
||||
},
|
||||
|
||||
toggleUnread: function(evt) {
|
||||
note = $(evt.target).closest(".stream_element");
|
||||
unread = note.hasClass("unread");
|
||||
var note = $(evt.target).closest(".stream_element");
|
||||
var unread = note.hasClass("unread");
|
||||
|
||||
if (unread) {
|
||||
this.setRead(note.data("guid"));
|
||||
}
|
||||
else {
|
||||
this.setUnread(note.data("guid"));
|
||||
}
|
||||
if (unread){ this.setRead(note.data("guid")); }
|
||||
else { this.setUnread(note.data("guid")); }
|
||||
},
|
||||
|
||||
setRead: function(guid) {
|
||||
$.ajax({
|
||||
url: "/notifications/" + guid,
|
||||
data: { set_unread: false },
|
||||
type: "PUT",
|
||||
context: this,
|
||||
success: this.clickSuccess
|
||||
});
|
||||
},
|
||||
getAllUnread: function(){ return $('.media.stream_element.unread'); },
|
||||
|
||||
setUnread: function(guid) {
|
||||
setRead: function(guid) { this.setUnreadStatus(guid, false); },
|
||||
|
||||
setUnread: function(guid){ this.setUnreadStatus(guid, true); },
|
||||
|
||||
setUnreadStatus: function(guid, state){
|
||||
$.ajax({
|
||||
url: "/notifications/" + guid,
|
||||
data: { set_unread: true },
|
||||
data: { set_unread: state },
|
||||
type: "PUT",
|
||||
context: this,
|
||||
success: this.clickSuccess
|
||||
|
|
@ -42,51 +37,58 @@ app.views.Notifications = Backbone.View.extend({
|
|||
},
|
||||
|
||||
clickSuccess: function(data) {
|
||||
type = $('.stream_element[data-guid=' + data["guid"] + ']').data('type');
|
||||
var type = $('.stream_element[data-guid=' + data["guid"] + ']').data('type');
|
||||
this.updateView(data["guid"], type, data["unread"]);
|
||||
},
|
||||
|
||||
markAllRead: function(evt){
|
||||
if(evt) { evt.preventDefault(); }
|
||||
var self = this;
|
||||
this.getAllUnread().each(function(i, el){
|
||||
self.setRead($(el).data("guid"));
|
||||
});
|
||||
},
|
||||
|
||||
updateView: function(guid, type, unread) {
|
||||
change = unread ? 1 : -1;
|
||||
all_notes = $('ul.nav > li:eq(0) .badge');
|
||||
type_notes = $('ul.nav > li[data-type=' + type + '] .badge');
|
||||
header_badge = $('#notification_badge .badge_count');
|
||||
var change = unread ? 1 : -1,
|
||||
all_notes = $('ul.nav > li:eq(0) .badge'),
|
||||
type_notes = $('ul.nav > li[data-type=' + type + '] .badge'),
|
||||
header_badge = $('#notification_badge .badge_count'),
|
||||
note = $('.stream_element[data-guid=' + guid + ']'),
|
||||
markAllReadLink = $('a#mark_all_read_link'),
|
||||
translationKey = unread ? 'notifications.mark_read' : 'notifications.mark_unread';
|
||||
|
||||
note = $('.stream_element[data-guid=' + guid + ']');
|
||||
if(unread) {
|
||||
note.removeClass("read").addClass("unread");
|
||||
$(".unread-toggle .entypo", note)
|
||||
if(unread){ note.removeClass("read").addClass("unread"); }
|
||||
else { note.removeClass("unread").addClass("read"); }
|
||||
|
||||
$(".unread-toggle .entypo", note)
|
||||
.tooltip('destroy')
|
||||
.removeAttr("data-original-title")
|
||||
.attr('title',Diaspora.I18n.t('notifications.mark_read'))
|
||||
.attr('title',Diaspora.I18n.t(translationKey))
|
||||
.tooltip();
|
||||
}
|
||||
else {
|
||||
note.removeClass("unread").addClass("read");
|
||||
$(".unread-toggle .entypo", note)
|
||||
.tooltip('destroy')
|
||||
.removeAttr("data-original-title")
|
||||
.attr('title',Diaspora.I18n.t('notifications.mark_unread'))
|
||||
.tooltip();
|
||||
}
|
||||
|
||||
all_notes.text( function(i,text) { return parseInt(text) + change });
|
||||
type_notes.text( function(i,text) { return parseInt(text) + change });
|
||||
header_badge.text( function(i,text) { return parseInt(text) + change });
|
||||
if(all_notes.text()>0){
|
||||
all_notes.addClass('badge-important').removeClass('badge-default');
|
||||
} else {
|
||||
all_notes.removeClass('badge-important').addClass('badge-default');
|
||||
}
|
||||
if(type_notes.text()>0){
|
||||
type_notes.addClass('badge-important').removeClass('badge-default');
|
||||
} else {
|
||||
type_notes.removeClass('badge-important').addClass('badge-default');
|
||||
}
|
||||
if(header_badge.text()>0){
|
||||
[all_notes, type_notes, header_badge].forEach(function(element){
|
||||
element.text(function(i, text){
|
||||
return parseInt(text) + change });
|
||||
});
|
||||
|
||||
[all_notes, type_notes].forEach(function(badge) {
|
||||
if(badge.text() > 0) {
|
||||
badge.addClass('badge-important').removeClass('badge-default');
|
||||
}
|
||||
else {
|
||||
badge.removeClass('badge-important').addClass('badge-default');
|
||||
}
|
||||
});
|
||||
|
||||
if(header_badge.text() > 0){
|
||||
header_badge.removeClass('hidden');
|
||||
} else {
|
||||
markAllReadLink.removeClass('disabled');
|
||||
}
|
||||
else{
|
||||
header_badge.addClass('hidden');
|
||||
markAllReadLink.addClass('disabled');
|
||||
}
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Photo = app.views.Base.extend({
|
||||
|
||||
templateName: "photo",
|
||||
|
|
@ -8,11 +10,10 @@ app.views.Photo = app.views.Base.extend({
|
|||
"click .remove_post": "destroyModel"
|
||||
},
|
||||
|
||||
tooltipSelector : ".block_user, .delete",
|
||||
tooltipSelector : ".control-icons a",
|
||||
|
||||
initialize : function() {
|
||||
$(this.el).attr("id", this.model.get("guid"));
|
||||
this.model.bind('remove', this.remove, this);
|
||||
return this;
|
||||
},
|
||||
|
||||
|
|
@ -22,3 +23,5 @@ app.views.Photo = app.views.Base.extend({
|
|||
});
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,10 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.PhotoViewer = app.views.Base.extend({
|
||||
templateName : "photo-viewer",
|
||||
|
||||
presenter : function(){
|
||||
return { photos : this.model.get("photos") } //json array of attributes, not backbone models, yet.
|
||||
return { photos : this.model.get("photos") }; //json array of attributes, not backbone models, yet.
|
||||
}
|
||||
});
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||
|
|
@ -1,13 +1,15 @@
|
|||
// @license magnet:?xt=urn:btih:0b31508aeb0634b347b8270c7bee4d411b5d4109&dn=agpl-3.0.txt AGPL-v3-or-Later
|
||||
|
||||
app.views.Photos = app.views.InfScroll.extend({
|
||||
initialize : function(options) {
|
||||
initialize : function() {
|
||||
this.stream = this.model;
|
||||
this.collection = this.stream.items;
|
||||
|
||||
// viable for extraction
|
||||
this.stream.fetch();
|
||||
|
||||
this.setupLightbox()
|
||||
this.setupInfiniteScroll()
|
||||
this.setupLightbox();
|
||||
this.setupInfiniteScroll();
|
||||
},
|
||||
|
||||
postClass : app.views.Photo,
|
||||
|
|
@ -21,3 +23,4 @@ app.views.Photos = app.views.InfScroll.extend({
|
|||
$(this.el).delegate("a.photo-link", "click", this.lightbox.lightboxImageClicked);
|
||||
}
|
||||
});
|
||||
// @license-end
|
||||
|
|
|
|||