Merge remote-tracking branch 'upstream/develop' into 1606-contact-priority

This commit is contained in:
Michael Vogel 2016-06-12 12:16:24 +02:00
commit c138455c5e
24 changed files with 918 additions and 104 deletions

View file

@ -154,18 +154,6 @@ Friendica also supports a number on non-standard headers in common use.
X-Forwarded-Ssl: on
It is however preferable to use the standard approach if configuring a new server.
In Nginx, this can be done as follows (assuming Friendica runs on port 8080).
location / {
if ( $scheme != https ) { # Force Redirect to HTTPS
return 302 https://$host$uri;
}
proxy_pass http://localhost:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Forwarded "for=$proxy_add_x_forwarded_for; proto=$scheme";
}
#####################################################################

View file

@ -282,17 +282,17 @@ function admin_page_federation(&$a) {
foreach ($platforms as $p) {
// get a total count for the platform, the name and version of the
// highest version and the protocol tpe
$c = q('SELECT count(*) AS total, platform, network, version FROM gserver
WHERE platform LIKE "%s" AND last_contact > last_failure AND `version` != ""
ORDER BY version ASC;', $p);
$c = q('SELECT COUNT(*) AS `total`, `platform`, `network`, `version` FROM `gserver`
WHERE `platform` LIKE "%s" AND `last_contact` > `last_failure` AND `version` != ""
ORDER BY `version` ASC;', $p);
$total = $total + $c[0]['total'];
// what versions for that platform do we know at all?
// again only the active nodes
$v = q('SELECT count(*) AS total, version FROM gserver
WHERE last_contact > last_failure AND platform LIKE "%s" AND `version` != ""
GROUP BY version
ORDER BY version;', $p);
$v = q('SELECT COUNT(*) AS `total, version` FROM `gserver`
WHERE `last_contact` > `last_failure` AND `platform` LIKE "%s" AND `version` != ""
GROUP BY `version`
ORDER BY `version`;', $p);
//
// clean up version numbers
@ -386,7 +386,10 @@ function admin_page_federation(&$a) {
*/
function admin_page_queue(&$a) {
// get content from the queue table
$r = q("SELECT c.name,c.nurl,q.id,q.network,q.created,q.last from queue as q, contact as c where c.id=q.cid order by q.cid, q.created;");
$r = q("SELECT `c`.`name`, `c`.`nurl`, `q`.`id`, `q`.`network`, `q`.`created`, `q`.`last`
FROM `queue` AS `q`, `contact` AS `c`
WHERE `c`.`id` = `q`.`cid`
ORDER BY `q`.`cid`, `q`.`created`;");
$t = get_markup_template("admin_queue.tpl");
return replace_macros($t, array(
@ -416,7 +419,7 @@ function admin_page_queue(&$a) {
* @return string
*/
function admin_page_summary(&$a) {
$r = q("SELECT `page-flags`, COUNT(uid) as `count` FROM `user` GROUP BY `page-flags`");
$r = q("SELECT `page-flags`, COUNT(`uid`) AS `count` FROM `user` GROUP BY `page-flags`");
$accounts = array(
array(t('Normal Account'), 0),
array(t('Soapbox Account'), 0),
@ -431,17 +434,17 @@ function admin_page_summary(&$a) {
logger('accounts: '.print_r($accounts,true),LOGGER_DATA);
$r = q("SELECT COUNT(id) as `count` FROM `register`");
$r = q("SELECT COUNT(`id`) AS `count` FROM `register`");
$pending = $r[0]['count'];
$r = q("select count(*) as total from deliverq where 1");
$r = q("SELECT COUNT(*) AS `total` FROM `deliverq` WHERE 1");
$deliverq = (($r) ? $r[0]['total'] : 0);
$r = q("select count(*) as total from queue where 1");
$r = q("SELECT COUNT(*) AS `total` FROM `queue` WHERE 1");
$queue = (($r) ? $r[0]['total'] : 0);
if (get_config('system','worker')) {
$r = q("select count(*) as total from workerqueue where 1");
$r = q("SELECT COUNT(*) AS `total` FROM `workerqueue` WHERE 1");
$workerqueue = (($r) ? $r[0]['total'] : 0);
} else {
$workerqueue = 0;
@ -543,7 +546,7 @@ function admin_page_site_post(&$a) {
set_config('system','url',$new_url);
// send relocate
$users = q("SELECT uid FROM user WHERE account_removed = 0 AND account_expired = 0");
$users = q("SELECT `uid` FROM `user` WHERE `account_removed` = 0 AND `account_expired` = 0");
foreach ($users as $user) {
proc_run('php', 'include/notifier.php', 'relocate', $user['uid']);
@ -647,41 +650,41 @@ function admin_page_site_post(&$a) {
if($ssl_policy != intval(get_config('system','ssl_policy'))) {
if($ssl_policy == SSL_POLICY_FULL) {
q("update `contact` set
`url` = replace(`url` , 'http:' , 'https:'),
`photo` = replace(`photo` , 'http:' , 'https:'),
`thumb` = replace(`thumb` , 'http:' , 'https:'),
`micro` = replace(`micro` , 'http:' , 'https:'),
`request` = replace(`request`, 'http:' , 'https:'),
`notify` = replace(`notify` , 'http:' , 'https:'),
`poll` = replace(`poll` , 'http:' , 'https:'),
`confirm` = replace(`confirm`, 'http:' , 'https:'),
`poco` = replace(`poco` , 'http:' , 'https:')
where `self` = 1"
q("UPDATE `contact` SET
`url` = REPLACE(`url` , 'http:' , 'https:'),
`photo` = REPLACE(`photo` , 'http:' , 'https:'),
`thumb` = REPLACE(`thumb` , 'http:' , 'https:'),
`micro` = REPLACE(`micro` , 'http:' , 'https:'),
`request` = REPLACE(`request`, 'http:' , 'https:'),
`notify` = REPLACE(`notify` , 'http:' , 'https:'),
`poll` = REPLACE(`poll` , 'http:' , 'https:'),
`confirm` = REPLACE(`confirm`, 'http:' , 'https:'),
`poco` = REPLACE(`poco` , 'http:' , 'https:')
WHERE `self` = 1"
);
q("update `profile` set
`photo` = replace(`photo` , 'http:' , 'https:'),
`thumb` = replace(`thumb` , 'http:' , 'https:')
where 1 "
q("UPDATE `profile` SET
`photo` = REPLACE(`photo` , 'http:' , 'https:'),
`thumb` = REPLACE(`thumb` , 'http:' , 'https:')
WHERE 1 "
);
}
elseif($ssl_policy == SSL_POLICY_SELFSIGN) {
q("update `contact` set
`url` = replace(`url` , 'https:' , 'http:'),
`photo` = replace(`photo` , 'https:' , 'http:'),
`thumb` = replace(`thumb` , 'https:' , 'http:'),
`micro` = replace(`micro` , 'https:' , 'http:'),
`request` = replace(`request`, 'https:' , 'http:'),
`notify` = replace(`notify` , 'https:' , 'http:'),
`poll` = replace(`poll` , 'https:' , 'http:'),
`confirm` = replace(`confirm`, 'https:' , 'http:'),
`poco` = replace(`poco` , 'https:' , 'http:')
where `self` = 1"
q("UPDATE `contact` SET
`url` = REPLACE(`url` , 'https:' , 'http:'),
`photo` = REPLACE(`photo` , 'https:' , 'http:'),
`thumb` = REPLACE(`thumb` , 'https:' , 'http:'),
`micro` = REPLACE(`micro` , 'https:' , 'http:'),
`request` = REPLACE(`request`, 'https:' , 'http:'),
`notify` = REPLACE(`notify` , 'https:' , 'http:'),
`poll` = REPLACE(`poll` , 'https:' , 'http:'),
`confirm` = REPLACE(`confirm`, 'https:' , 'http:'),
`poco` = REPLACE(`poco` , 'https:' , 'http:')
WHERE `self` = 1"
);
q("update `profile` set
`photo` = replace(`photo` , 'https:' , 'http:'),
`thumb` = replace(`thumb` , 'https:' , 'http:')
where 1 "
q("UPDATE `profile` SET
`photo` = REPLACE(`photo` , 'https:' , 'http:'),
`thumb` = REPLACE(`thumb` , 'https:' , 'http:')
WHERE 1 "
);
}
}
@ -876,7 +879,7 @@ function admin_page_site(&$a) {
/* get user names to make the install a personal install of X */
$user_names = array();
$user_names['---'] = t('Multi user instance');
$users = q("SELECT username, nickname FROM `user`");
$users = q("SELECT `username`, `nickname` FROM `user`");
foreach ($users as $user) {
$user_names[$user['nickname']] = $user['username'];
}
@ -1084,7 +1087,7 @@ function admin_page_dbsync(&$a) {
}
$failed = array();
$r = q("select k, v from config where `cat` = 'database' ");
$r = q("SELECT `k`, `v` FROM `config` WHERE `cat` = 'database' ");
if(count($r)) {
foreach($r as $rr) {
$upd = intval(substr($rr['k'],7));
@ -1225,7 +1228,7 @@ function admin_page_users_post(&$a){
function admin_page_users(&$a){
if($a->argc>2) {
$uid = $a->argv[3];
$user = q("SELECT username, blocked FROM `user` WHERE `uid`=%d", intval($uid));
$user = q("SELECT `username`, `blocked` FROM `user` WHERE `uid` = %d", intval($uid));
if(count($user)==0) {
notice('User not found'.EOL);
goaway('admin/users');
@ -1262,7 +1265,7 @@ function admin_page_users(&$a){
/* get users */
$total = q("SELECT count(*) as total FROM `user` where 1");
$total = q("SELECT COUNT(*) AS `total` FROM `user` WHERE 1");
if(count($total)) {
$a->set_pager_total($total[0]['total']);
$a->set_pager_itemspage(100);

View file

@ -787,7 +787,7 @@ function contacts_content(&$a) {
'$total' => $total,
'$search' => $search_hdr,
'$desc' => t('Search your contacts'),
'$finding' => (($searching) ? t('Finding: ') . "'" . $search . "'" : ""),
'$finding' => (($searching) ? sprintf(t('Results for: %s'),$search) : ""),
'$submit' => t('Find'),
'$cmd' => $a->cmd,
'$contacts' => $contacts,

View file

@ -206,7 +206,7 @@ function directory_content(&$a) {
'$gdirpath' => $gdirpath,
'$desc' => t('Find on this site'),
'$contacts' => $entries,
'$finding' => t('Finding:'),
'$finding' => t('Results for:'),
'$findterm' => (strlen($search) ? $search : ""),
'$title' => t('Site Directory'),
'$submit' => t('Find'),

View file

@ -33,6 +33,7 @@ function dirfind_content(&$a, $prefix = "") {
if(strpos($search,'@') === 0) {
$search = substr($search,1);
$header = sprintf( t('People Search - %s'), $search);
if ((valid_email($search) AND validate_email($search)) OR
(substr(normalise_link($search), 0, 7) == "http://")) {
$user_data = probe_url($search);
@ -43,6 +44,7 @@ function dirfind_content(&$a, $prefix = "") {
if(strpos($search,'!') === 0) {
$search = substr($search,1);
$community = true;
$header = sprintf( t('Forum Search - %s'), $search);
}
$o = '';
@ -228,7 +230,7 @@ function dirfind_content(&$a, $prefix = "") {
$tpl = get_markup_template('viewcontact_template.tpl');
$o .= replace_macros($tpl,array(
'title' => sprintf( t('People Search - %s'), $search),
'title' => $header,
'$contacts' => $entries,
'$paginate' => paginate($a),
));

View file

@ -0,0 +1,30 @@
#
# Example of NGINX as reverse-proxy terminating an HTTPS connection.
#
# This is not a complete NGINX config.
#
# Please refer to NGINX docs
#
...
server {
...
# assuming Friendica runs on port 8080
location / {
if ( $scheme != https ) {
# Force Redirect to HTTPS
return 302 https://$host$uri;
}
proxy_pass http://localhost:8080;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Forwarded "for=$proxy_add_x_forwarded_for; proto=$scheme";
}
...
}

View file

@ -581,6 +581,9 @@ nav.navbar a {
margin: 0px;
padding: 10px 15px;
}
#search-mobile .navbar-form {
margin: 0;
}
#topbar-first #search-box .form-search {
height: 25px;
font-size: 13px;
@ -941,6 +944,55 @@ aside .vcard #dfrn-request-link,
aside .vcard #wallmessage-link {
width: 100%;
}
/* vcard-short-info */
#vcard-short-info,
#nav-short-info .contact-wrapper {
margin-top: 2px;
height: 40px;
white-space: nowrap;
overflow: hidden;
padding-right: 20px;
margin-left: -14px;
}
#vcard-short-photo-wrapper img,
#nav-short-info .contact-wrapper img {
height: 34px;
width: 34px;
border-radius: 3px;
}
#vcard-short-desc,
#nav-short-info .contact-wrapper .media-body {
display: block;
height: 34px;
width: 100%;
text-overflow: ellipsis;
}
#vcard-short-desc > .media-heading,
#vcard-short-desc > .vcard-short-addr,
#nav-short-info .contact-wrapper .media-heading,
#nav-short-info .contact-wrapper #contact-entry-url-network {
text-overflow: ellipsis;
overflow: hidden;
}
#vcard-short-desc > .media-heading,
#nav-short-info .contact-wrapper .media-heading {
margin-bottom: 1px;
font-weight: bold;
}
#nav-short-info .contact-wrapper .media-heading a {
color: #555;
font-size: 14px !important;
}
#vcard-short-desc > .vcard-short-addr,
#nav-short-info .contact-wrapper #contact-entry-url-network {
color: #777;
font-size: 12px;
}
.network-content-wrapper > #viewcontact_wrapper-network,
#nav-short-info .contact-wrapper .contact-photo-overlay,
#nav-short-info .contact-wrapper .contact-actions{
display: none
}
aside #peoplefind-sidebar input,
aside #follow-sidebar input {
@ -1531,6 +1583,11 @@ img.acpopup-img {
/*margin-left: -15px;*/
padding: 0;
}
#tabmenu .search-heading {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
ul.tabs {
list-style: none;
height: 100%;
@ -1661,6 +1718,15 @@ ul.dropdown-menu li:hover {
color: $link_color;
font-size: 20px;
}
.search-content-wrapper > #search-header-wrapper {
display: none;
}
.search-content-wrapper > .section-title-wrapper {
display: none;
}
#navbar-button > #search-save-form > #search-save {
margin-top: 3px;
}
/* Section-Content-Wrapper */
#search-header-wrapper {
padding: 15px;

View file

@ -0,0 +1,183 @@
# NOTE: This is the latest version of ScrollSpy, which includes a ton of bug fixes and efficiency improvements. It's recommended that you use this version for now instead of the official (which hasn't been updated in a while).
# jQuery-ScrollSpy
An adaptation of the Mootools Scrollspy (http://davidwalsh.name/mootools-scrollspy) plugin for jQuery
(c) 2011 Samuel Alexander (https://github.com/sxalexander/jquery-scrollspy)
(c) 2015 SoftwareSpot
Released under The MIT License.
## Description:
ScrollSpy is a simple jQuery plugin for firing events based on where the user has scrolled to in a page.
## Homepage:
https://github.com/softwarespot/jquery-scrollspy
## Source:
Hosted at GitHub; browse at:
https://github.com/softwarespot/jquery-scrollspy/tree/master
Or clone from:
git://github.com/softwarespot/jquery-scrollspy.git
## Usage:
1. Insert the necessary elements in to your document's `<head>` section, e.g.:
```html
<script src="jquery.min.js"></script>
<script src="jquery.scrollspy.min.js"></script>
```
2. Initialise ScrollSpy once the DOM has been loaded:
```javascript
<script>
$(function() {
var $nav = $('#nav');
$('#sticky-navigation').scrollspy({
min: $nav.offset().top,
onEnter: function(element, position) {
$nav.addClass('fixed');
},
onLeave: function(element, position) {
$nav.removeClass('fixed');
}
});
});
</script>
```
Check out the /examples for more info !
## Documentation:
ScrollSpy function signature:
```javascript
$('container').scrollspy(options, action)
```
Default options for ScrollSpy:
```javascript
// default options for ScrollSpy
var defaults = {
// the offset to be applied to the left and top positions of the container
buffer: 0,
// the element to apply the 'scrolling' event to (default window)
container: window,
// the maximum value of the X or Y coordinate, depending on mode the selected
max: 0,
// the maximum value of the X or Y coordinate, depending on mode the selected
min: 0,
// whether to listen to the X (horizontal) or Y (vertical) scrolling
mode: 'vertical',
// namespace to append to the 'scroll' event
namespace: 'scrollspy',
// call the following callback function every time the user enters the min / max zone
onEnter: null,
// call the following callback function every time the user leaves the min / max zone
onLeave: null,
// call the following callback function every time the user leaves the top zone
onLeaveTop: null,
// call the following callback function every time the user leaves the bottom zone
onLeaveBottom: null,
// call the following callback function on each scroll event within the min and max parameters
onTick: null,
// call the following callback function on each scroll event when the element is inside the viewable view port
onView: null
};
```
Events are triggered by ScrollSpy are:
scrollTick: Fires on each scroll event within the min and max parameters:
position: an object with the current X and Y position.
inside: a Boolean value for whether or not the user is within the min and max parameters
enters: the number of times the min / max has been entered.
leaves: the number of times the min / max has been left.
scrollEnter: Fires every time the user enters the min / max zone:
position: an object with the current X and Y position.
enters: the number of times the min / max has been entered.
scrollLeave: Fires every time the user leaves the min / max zone:
position: an object with the current X and Y position.
leaves: the number of times the min / max has been left.
scrollLeaveTop: Fires every time the user leaves the top zone:
position: an object with the current X and Y position.
leaves: the number of times the min / max has been left.
scrollLeaveBottom: Fires every time the user leaves the bottom zone:
position: an object with the current X and Y position.
leaves: the number of times the min / max has been left.
scrollView: Fires every time the element is inside the viewable view port:
position: an object with the current X and Y position.
leaves: the number of times the min / max has been left.
### Tidy up
To destroy ScrollSpy for a particular container, simple pass 'destroy' as the action parameter. The only options that will be honoured are `container` and `namespace`.
## A note about forking:
By forking this project you hereby grant permission for any commits to your fork to be
merged back into this repository and, with attribution, be released under the terms of
the MIT License.
## Contribute
To contribute to the project, you will first need to install [node](https://nodejs.org) globally on your system. Once installation has completed, change the working directory to the plugin's location and run the following command:
```shell
npm install
```
After installation of the local modules, you're ready to start contributing to the project. Before you submit your PR, please don't forget to call `gulp`, which will run against [JSHint](http://jshint.com) for any errors, but will also minify the plugin.
##### Watch
Call the following command to start 'watching' for any changes to the main JavaScript file(s). This will automatically invoke JSHint and Uglify.
```shell
gulp watch
```
##### JSHint
Call the following command to invoke JSHint and check that the changes meet the requirements set in .jshintrc.
```shell
gulp jshint
```
##### Uglify
Call the following command to invoke Uglify, which will minify the main JavaScript file(s) and output to a .min.js file respectively.
```shell
gulp uglify
```
##### Build
Call the following command to invoke both JSHint and Uglify.
```shell
gulp
```

View file

@ -0,0 +1,18 @@
{
"name": "jquery-scrollspy",
"homepage": "https://github.com/sxalexander/jquery-scrollspy/",
"description": "scrollspy is a simple jQuery plugin for firing events based on where the user has scrolled to in a page.",
"main": "jquery-scrollspy.min.js",
"keywords": [
"scrolling",
"scroll"
],
"license": "MIT",
"ignore": [
],
"dependencies": {
"jquery": ">=1.7.0"
},
"devDependencies": {
}
}

View file

@ -0,0 +1,65 @@
/* global require */
var gulp = require('gulp');
var eslint = require('gulp-eslint');
var gulpIf = require('gulp-if');
var rename = require('gulp-rename');
var uglify = require('gulp-uglify');
// Assets for the project
var Assets = {
main: './jquery-scrollspy.js',
minified: './jquery-scrollspy.min.js',
package: './package.json',
readme: './README.md',
source: './',
};
// See the uglify documentation for more details
var _uglifySettings = {
compress: {
comparisons: true,
conditionals: true,
/* jscs: disable */
dead_code: true,
drop_console: true,
/* jscs: enable */
unsafe: true,
unused: true,
},
};
// Check the main js file(s) meets the following standards outlined in .eslintrc
gulp.task('eslint', function esLintTask() {
// Has ESLint fixed the file contents?
function isFixed(file) {
return file.eslint !== undefined && file.eslint !== null && file.eslint.fixed;
}
return gulp.src(Assets.main)
.pipe(eslint({
fix: true,
useEslintrc: '.eslintrc',
}))
.pipe(eslint.format())
.pipe(gulpIf(isFixed, gulp.dest(Assets.source)));
});
// Uglify aka minify the main file
gulp.task('uglify', function uglifyTask() {
return gulp.src(Assets.main)
.pipe(uglify(_uglifySettings))
.pipe(rename(Assets.minified))
.pipe(gulp.dest(Assets.source));
});
// Watch for changes to the main file
gulp.task('watch', function watchTask() {
gulp.watch(Assets.main, ['eslint', 'uglify']);
});
// Register the default task
gulp.task('default', ['eslint', 'uglify']);
// 'gulp eslint' to check the syntax of the main js file(s)
// 'gulp uglify' to uglify the main file

View file

@ -0,0 +1,267 @@
/*
* jQuery ScrollSpy Plugin
* Author: @sxalexander, softwarespot
* Licensed under the MIT license
*/
(function jQueryScrollspy(window, $) {
// Plugin Logic
$.fn.extend({
scrollspy: function scrollspy(options, action) {
// If the options parameter is a string, then assume it's an 'action', therefore swap the parameters around
if (_isString(options)) {
var tempOptions = action;
// Set the action as the option parameter
action = options;
// Set to be the reference action pointed to
options = tempOptions;
}
// override the default options with those passed to the plugin
options = $.extend({}, _defaults, options);
// sanitize the following option with the default value if the predicate fails
_sanitizeOption(options, _defaults, 'container', _isObject);
// cache the jQuery object
var $container = $(options.container);
// check if it's a valid jQuery selector
if ($container.length === 0) {
return this;
}
// sanitize the following option with the default value if the predicate fails
_sanitizeOption(options, _defaults, 'namespace', _isString);
// check if the action is set to DESTROY/destroy
if (_isString(action) && action.toUpperCase() === 'DESTROY') {
$container.off('scroll.' + options.namespace);
return this;
}
// sanitize the following options with the default values if the predicates fails
_sanitizeOption(options, _defaults, 'buffer', $.isNumeric);
_sanitizeOption(options, _defaults, 'max', $.isNumeric);
_sanitizeOption(options, _defaults, 'min', $.isNumeric);
// callbacks
_sanitizeOption(options, _defaults, 'onEnter', $.isFunction);
_sanitizeOption(options, _defaults, 'onLeave', $.isFunction);
_sanitizeOption(options, _defaults, 'onLeaveTop', $.isFunction);
_sanitizeOption(options, _defaults, 'onLeaveBottom', $.isFunction);
_sanitizeOption(options, _defaults, 'onTick', $.isFunction);
if ($.isFunction(options.max)) {
options.max = options.max();
}
if ($.isFunction(options.min)) {
options.min = options.min();
}
// check if the mode is set to VERTICAL/vertical
var isVertical = window.String(options.mode).toUpperCase() === 'VERTICAL';
return this.each(function each() {
// cache this
var _this = this;
// cache the jQuery object
var $element = $(_this);
// count the number of times a container is entered
var enters = 0;
// determine if the scroll is with inside the container
var inside = false;
// count the number of times a container is left
var leaves = 0;
// create a scroll listener for the container
$container.on('scroll.' + options.namespace, function onScroll() {
// cache the jQuery object
var $this = $(this);
// create a position object literal
var position = {
top: $this.scrollTop(),
left: $this.scrollLeft(),
};
var containerHeight = $container.height();
var max = options.max;
var min = options.min;
var xAndY = isVertical ? position.top + options.buffer : position.left + options.buffer;
if (max === 0) {
// get the maximum value based on either the height or the outer width
max = isVertical ? containerHeight : $container.outerWidth() + $element.outerWidth();
}
// if we have reached the minimum bound, though are below the max
if (xAndY >= min && xAndY <= max) {
// trigger the 'scrollEnter' event
if (!inside) {
inside = true;
enters++;
// trigger the 'scrollEnter' event
$element.trigger('scrollEnter', {
position: position,
});
// call the 'onEnter' function
if (options.onEnter !== null) {
options.onEnter(_this, position);
}
}
// trigger the 'scrollTick' event
$element.trigger('scrollTick', {
position: position,
inside: inside,
enters: enters,
leaves: leaves,
});
// call the 'onTick' function
if (options.onTick !== null) {
options.onTick(_this, position, inside, enters, leaves);
}
} else {
if (inside) {
inside = false;
leaves++;
// trigger the 'scrollLeave' event
$element.trigger('scrollLeave', {
position: position,
leaves: leaves,
});
// call the 'onLeave' function
if (options.onLeave !== null) {
options.onLeave(_this, position);
}
if (xAndY <= min) {
// trigger the 'scrollLeaveTop' event
$element.trigger('scrollLeaveTop', {
position: position,
leaves: leaves,
});
// call the 'onLeaveTop' function
if (options.onLeaveTop !== null) {
options.onLeaveTop(_this, position);
}
} else if (xAndY >= max) {
// trigger the 'scrollLeaveBottom' event
$element.trigger('scrollLeaveBottom', {
position: position,
leaves: leaves,
});
// call the 'onLeaveBottom' function
if (options.onLeaveBottom !== null) {
options.onLeaveBottom(_this, position);
}
}
} else {
// Idea taken from: http://stackoverflow.com/questions/5353934/check-if-element-is-visible-on-screen
var containerScrollTop = $container.scrollTop();
// Get the element height
var elementHeight = $element.height();
// Get the element offset
var elementOffsetTop = $element.offset().top;
if ((elementOffsetTop < (containerHeight + containerScrollTop)) && (elementOffsetTop > (containerScrollTop - elementHeight))) {
// trigger the 'scrollView' event
$element.trigger('scrollView', {
position: position,
});
// call the 'onView' function
if (options.onView !== null) {
options.onView(_this, position);
}
}
}
}
});
});
},
});
// Fields (Private)
// Defaults
// default options
var _defaults = {
// the offset to be applied to the left and top positions of the container
buffer: 0,
// the element to apply the 'scrolling' event to (default window)
container: window,
// the maximum value of the X or Y coordinate, depending on mode the selected
max: 0,
// the maximum value of the X or Y coordinate, depending on mode the selected
min: 0,
// whether to listen to the X (horizontal) or Y (vertical) scrolling
mode: 'vertical',
// namespace to append to the 'scroll' event
namespace: 'scrollspy',
// call the following callback function every time the user enters the min / max zone
onEnter: null,
// call the following callback function every time the user leaves the min / max zone
onLeave: null,
// call the following callback function every time the user leaves the top zone
onLeaveTop: null,
// call the following callback function every time the user leaves the bottom zone
onLeaveBottom: null,
// call the following callback function on each scroll event within the min and max parameters
onTick: null,
// call the following callback function on each scroll event when the element is inside the viewable view port
onView: null,
};
// Methods (Private)
// check if a value is an object datatype
function _isObject(value) {
return $.type(value) === 'object';
}
// check if a value is a string datatype with a length greater than zero when whitespace is stripped
function _isString(value) {
return $.type(value) === 'string' && $.trim(value).length > 0;
}
// check if an option is correctly formatted using a predicate; otherwise, return the default value
function _sanitizeOption(options, defaults, property, predicate) {
// set the property to the default value if the predicate returned false
if (!predicate(options[property])) {
options[property] = defaults[property];
}
}
}(window, window.jQuery));

View file

@ -0,0 +1 @@
!function(e,n){function o(e){return"object"===n.type(e)}function i(e){return"string"===n.type(e)&&n.trim(e).length>0}function t(e,n,o,i){i(e[o])||(e[o]=n[o])}n.fn.extend({scrollspy:function(l,s){if(i(l)){var a=s;s=l,l=a}l=n.extend({},r,l),t(l,r,"container",o);var c=n(l.container);if(0===c.length)return this;if(t(l,r,"namespace",i),i(s)&&"DESTROY"===s.toUpperCase())return c.off("scroll."+l.namespace),this;t(l,r,"buffer",n.isNumeric),t(l,r,"max",n.isNumeric),t(l,r,"min",n.isNumeric),t(l,r,"onEnter",n.isFunction),t(l,r,"onLeave",n.isFunction),t(l,r,"onLeaveTop",n.isFunction),t(l,r,"onLeaveBottom",n.isFunction),t(l,r,"onTick",n.isFunction),n.isFunction(l.max)&&(l.max=l.max()),n.isFunction(l.min)&&(l.min=l.min());var u="VERTICAL"===e.String(l.mode).toUpperCase();return this.each(function(){var e=this,o=n(e),i=0,t=!1,r=0;c.on("scroll."+l.namespace,function(){var s=n(this),a={top:s.scrollTop(),left:s.scrollLeft()},f=c.height(),p=l.max,m=l.min,v=u?a.top+l.buffer:a.left+l.buffer;if(0===p&&(p=u?f:c.outerWidth()+o.outerWidth()),v>=m&&p>=v)t||(t=!0,i++,o.trigger("scrollEnter",{position:a}),null!==l.onEnter&&l.onEnter(e,a)),o.trigger("scrollTick",{position:a,inside:t,enters:i,leaves:r}),null!==l.onTick&&l.onTick(e,a,t,i,r);else if(t)t=!1,r++,o.trigger("scrollLeave",{position:a,leaves:r}),null!==l.onLeave&&l.onLeave(e,a),m>=v?(o.trigger("scrollLeaveTop",{position:a,leaves:r}),null!==l.onLeaveTop&&l.onLeaveTop(e,a)):v>=p&&(o.trigger("scrollLeaveBottom",{position:a,leaves:r}),null!==l.onLeaveBottom&&l.onLeaveBottom(e,a));else{var g=c.scrollTop(),L=o.height(),h=o.offset().top;f+g>h&&h>g-L&&(o.trigger("scrollView",{position:a}),null!==l.onView&&l.onView(e,a))}})})}});var r={buffer:0,container:e,max:0,min:0,mode:"vertical",namespace:"scrollspy",onEnter:null,onLeave:null,onLeaveTop:null,onLeaveBottom:null,onTick:null,onView:null}}(window,window.jQuery);

View file

@ -0,0 +1,21 @@
{
"name": "jquery-scrollspy",
"version": "1.0.0",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/softwarespot/jquery-scrollspy.git"
},
"devDependencies": {
"del": "^2.1.0",
"eslint": "^2.5.1",
"eslint-config-airbnb": "^6.2.0",
"gulp": "^3.9.1",
"gulp-eslint": "^2.0.0",
"gulp-if": "^2.0.0",
"gulp-rename": "~1.2.2",
"gulp-replace": "^0.5.4",
"gulp-uglify": "^1.5.3",
"merge2": "^1.0.1"
}
}

View file

@ -19,7 +19,7 @@ $(document).ready(function(){
// restore cached jot at its hidden position ("#jot-content")
$("#jot-content").append(jotcache);
// clear the jotcache
jotcache = ''
jotcache = '';
});
// Add Colorbox for viewing Network page images
@ -50,7 +50,11 @@ $(document).ready(function(){
}
});
// Navbar login
$("body").on("click", "#nav-login", function(e){
e.preventDefault();
Dialog.show(this.href, this.dataset.originalTitle || this.title);
});
// Jot nav menu.
$("body").on("click", "#jot-modal .jot-nav li a", function(e){
@ -60,7 +64,7 @@ $(document).ready(function(){
// Open filebrowser for elements with the class "image-select"
// The following part handles the filebrowser for field_fileinput.tpl
$("body").on("click", ".image-select", function(e){
$("body").on("click", ".image-select", function(){
// set a extra attribute to mark the clicked button
this.setAttribute("image-input", "select");
Dialog.doImageBrowser("input");
@ -69,7 +73,7 @@ $(document).ready(function(){
// Insert filebrowser images into the input field (field_fileinput.tpl)
$("body").on("fbrowser.image.input", function(e, filename, embedcode, id, img) {
// select the clicked button by it's attribute
var elm = $("[image-input='select']")
var elm = $("[image-input='select']");
// select the input field which belongs to this button
var input = elm.parent(".input-group").children("input");
// remove the special indicator attribut from the button
@ -81,8 +85,9 @@ $(document).ready(function(){
});
// overwrite Dialog.show from main js to load the filebrowser into a bs modal
Dialog.show = function(url) {
Dialog.show = function(url, title="") {
var modal = $('#modal').modal();
modal.find("#modal-header h4").html(title);
modal
.find('#modal-body')
.load(url, function (responseText, textStatus) {
@ -129,12 +134,13 @@ Dialog._load = function(url) {
// try to fetch the hash form the url
var match = url.match(/fbrowser\/[a-z]+\/\?mode=none(.*)/);
if (match===null) return; //not fbrowser
var hash = match[1];
// initialize the filebrowser
var jsbrowser = function() {
FileBrowser.init(nickname, type, hash);
}
};
loadScript("view/theme/frio/js/filebrowser.js", jsbrowser);
};
@ -166,7 +172,7 @@ function loadModalTitle() {
function addToModal(url) {
var char = qOrAmp(url);
var url = url + char + 'mode=none';
url = url + char + 'mode=none';
var modal = $('#modal').modal();
modal
@ -182,7 +188,7 @@ function addToModal(url) {
loadModalTitle();
}
});
};
}
// function to load the html from the edit post page into
// the jot modal
@ -201,7 +207,7 @@ function editpost(url) {
}
var modal = $('#jot-modal').modal();
var url = url + " #profile-jot-form";
url = url + " #profile-jot-form";
//var rand_num = random_digits(12);
$(".jot-nav #jot-perms-lnk").parent("li").hide();

View file

@ -40,7 +40,7 @@ $(document).ready(function(){
$(".field.select > select, .field.custom > select").addClass("form-control");
// move the tabbar to the second nav bar
if( $("ul.tabbar")) {
if( $("ul.tabbar").length ) {
$("ul.tabbar").appendTo("#topbar-second > .container > #tabmenu");
}
@ -50,7 +50,7 @@ $(document).ready(function(){
// to the friendica logo (the mask is in nav.tpl at the botom). To make it work we need to apply the
// correct url. The only way which comes to my mind was to do this with js
// So we apply the correct url (with the link to the id of the mask) after the page is loaded.
if($("#logo-img")) {
if($("#logo-img").length ) {
var pageurl = "url('" + window.location.href + "#logo-mask')";
$("#logo-img").css({"mask": pageurl});
}
@ -66,7 +66,7 @@ $(document).ready(function(){
});
// add Jot botton to the scecond navbar
if( $("section #jotOpen")) {
if( $("section #jotOpen").length ) {
$("section #jotOpen").appendTo("#topbar-second > .container > #navbar-button");
if( $("#jot-popup").is(":hidden")) $("#topbar-second > .container > #navbar-button #jotOpen").hide();
}
@ -95,13 +95,6 @@ $(document).ready(function(){
}
});
// add search-heading to the scecond navbar
if( $(".search-heading")) {
$(".search-heading").appendTo("#topbar-second > .container > #tabmenu");
}
//$('ul.flex-nav').flexMenu();
// initialize the bootstrap tooltips
@ -120,7 +113,72 @@ $(document).ready(function(){
// initialize the bootstrap-select
$('.selectpicker').selectpicker();
// add search-heading to the seccond navbar
if( $(".search-heading").length) {
$(".search-heading").appendTo("#topbar-second > .container > #tabmenu");
}
// add search results heading to the second navbar
// and insert the search value to the top nav search input
if( $(".search-content-wrapper").length ) {
// get the text of the heading (we catch the plain text because we don't
// want to have a h4 heading in the navbar
var searchText = $(".section-title-wrapper > h2").text();
// insert the plain text in a <h4> heading and give it a class
var newText = '<h4 class="search-heading">'+searchText+'</h4>';
// append the new heading to the navbar
$("#topbar-second > .container > #tabmenu").append(newText);
// try to get the value of the original search input to insert it
// as value in the nav-search-input
var searchValue = $("#search-wrapper .form-group-search input").val();
// if the orignal search value isn't available use the location path as value
if( typeof searchValue === "undefined") {
// get the location path
var urlPath = window.location.search
// and split it up in its parts
var splitPath = urlPath.split(/(\?search?=)(.*$)/);
if(typeof splitPath[2] !== 'undefined') {
// decode the path (e.g to decode %40 to the character @)
var searchValue = decodeURIComponent(splitPath[2]);
}
}
if( typeof searchValue !== "undefined") {
$("#nav-search-input-field").val(searchValue);
}
}
// move the "Save the search" button to the second navbar
$(".search-content-wrapper #search-save-form ").appendTo("#topbar-second > .container > #navbar-button");
// append the vcard-short-info to the second nav after passing the element
// with .p-addr (vcard). Use scrollspy to get the scroll position.
if( $("aside .vcard .p-addr").length) {
$(".vcard .p-addr").scrollspy({
min: $(".vcard .p-addr").position().top - 50,
onLeaveTop: function onLeave(element) {
$("#vcard-short-info").fadeOut(500, function () {
$("#vcard-short-info").appendTo("#vcard-short-info-wrapper");
});
},
onEnter: function(element) {
$("#vcard-short-info").appendTo("#nav-short-info");
$("#vcard-short-info").fadeIn(500);
},
});
}
// move the forum contact information of the network page into the second navbar
if( $(".network-content-wrapper > #viewcontact_wrapper-network").length) {
// get the contact-wrapper element and append it to the second nav bar
// Note: We need the first() element with this class since at the present time we
// store also the js template information in the html code and thats why
// there are two elements with this class but we don't want the js template
$(".network-content-wrapper > #viewcontact_wrapper-network .contact-wrapper").first().appendTo("#nav-short-info");
}
});
//function commentOpenUI(obj, id) {
// $(document).unbind( "click.commentOpen", handler );

View file

@ -0,0 +1,7 @@
<div id="id_{{$field.0}}_wrapper" class="form-group field input openid">
<label for="id_{{$field.0}}" id="label_{{$field.0}}">{{$field.1}}</label>
<input class="form-control" name="{{$field.0}}" id="id_{{$field.0}}" type="text" value="{{$field.2|escape:'html'}}" aria-describedby="{{$field.0}}_tip">
<span id="{{$field.0}}_tip" class="help-block" role="tooltip">{{$field.3}}</span>
<div class="clear"></div>
</div>

View file

@ -0,0 +1,7 @@
<div id="id_{{$field.0}}_wrapper" class="form-group field input password">
<label for="id_{{$field.0}}" id="label_{{$field.0}}">{{$field.1}}{{if $field.4}}<span class="required"> {{$field.4}}</span>{{/if}}</label>
<input class="form-control" name="{{$field.0}}" id="id_{{$field.0}}" type="text" value="{{$field.2|escape:'html'}}" {{if $field.4 eq "required"}} required{{/if}}{{if $field.5 eq "autofocus"}} autofocus{{elseif $field.5}} {{$field.5}}{{/if}} aria-describedby="{{$field.0}}_tip">
<span id="{{$field.0}}_tip" class="help-block" role="tooltip">{{$field.3}}</span>
<div class="clear"></div>
</div>

View file

@ -73,6 +73,7 @@
<script type="text/javascript" src="view/theme/frio/frameworks/bootstrap-colorpicker/js/bootstrap-colorpicker.min.js"></script>
<script type="text/javascript" src="view/theme/frio/frameworks/flexMenu/flexmenu.custom.js"></script>
<script type="text/javascript" src="view/theme/frio/frameworks/jsmart/jsmart.custom.js"></script>
<script type="text/javascript" src="view/theme/frio/frameworks/jquery-scrollspy/jquery-scrollspy.js"></script>
{{* own js files *}}
<script type="text/javascript" src="view/theme/frio/js/theme.js"></script>

View file

@ -0,0 +1,40 @@
<form id="login-form" action="{{$dest_url}}" role="form" method="post" >
<div id="login-group" role="group" aria-labelledby="login-head">
<input type="hidden" name="auth-params" value="login" />
<div id="login-head" class="sr-only">{{$login}}</div>
<div id="login_standard">
{{include file="field_input.tpl" field=$lname}}
{{include file="field_password.tpl" field=$lpassword}}
</div>
{{if $openid}}
<div id="login_openid">
{{include file="field_openid.tpl" field=$lopenid}}
</div>
{{/if}}
{{include file="field_checkbox.tpl" field=$lremember}}
<div id="login-extra-links" class="list-unstyled">
{{if $register}}<a href="register" title="{{$register.title|escape:'html'}}" id="register-link">{{$register.desc}}</a>{{/if}}
<a href="lostpass" title="{{$lostpass|escape:'html'}}" id="lost-password-link" class="pull-right">{{$lostlink}}</a>
</div>
<div id="login-submit-wrapper" class="pull-right" >
<button type="submit" name="submit" id="login-submit-button" class="btn btn-primary" value="{{$login|escape:'html'}}">{{$login|escape:'html'}}</button>
</div>
<div class="clear"></div>
{{foreach $hiddens as $k=>$v}}
<input type="hidden" name="{{$k}}" value="{{$v|escape:'html'}}" />
{{/foreach}}
</div>
</form>
<script type="text/javascript"> $(document).ready(function() { $("#id_{{$lname.0}}").focus();} );</script>

View file

@ -27,7 +27,7 @@
<span class="sr-only">Toggle navigation</span>
<i class="fa fa-ellipsis-v"></i>
</button>
<button type="button" class="navbar-toggle collapsed pull-right" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<button type="button" class="navbar-toggle collapsed pull-right" data-toggle="collapse" data-target="#search-mobile" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle Search</span>
<i class="fa fa-search" style="color:#FFF;"></i>
</button>
@ -240,17 +240,34 @@
<div class="hidden-sm hidden-xs">
<ul class="nav navbar-nav navbar-right">
<li><a href="register" data-toggle="tooltip" title="{{$register.title}}"><i class="fa fa-street-view fa-fw"></i> {{$register.desc}}</a></li>
<li><a href="login?mode=none" data-toggle="tooltip" title="{{$login}}"><i class="fa fa-sign-in fa-fw"></i> {{$login}}</a></li>
<li>
<a href="login?mode=none" id="nav-login"
data-toggle="tooltip" title="{{$nav.login.3}}">
<i class="fa fa-sign-in fa-fw"></i>
</a>
</li>
</ul>
</div>
</div>
</nav>
{{/if}}
{{* provide a a search input for mobile view, which expands by pressing the search icon *}}
<div id="search-mobile" class="hidden-lg hidden-md collapse">
<form class="navbar-form" role="search" method="get" action="{{$nav.search.0}}">
<!-- <img class="hidden-xs" src="{{$nav.userinfo.icon}}" alt="{{$nav.userinfo.name}}" style="max-width:33px; max-height:33px; min-width:33px; min-height:33px; width:33px; height:33px;"> -->
<div class="form-group form-group-search">
<input id="nav-search-input-field-mobile" class="form-control form-search" type="text" name="search" data-toggle="tooltip" title="{{$search_hint}}" placeholder="{{$nav.search.1}}">
<button class="btn btn-default btn-sm form-button-search" type="submit">{{$nav.search.1}}</button>
</div>
</form>
</div>
{{* The second navbar which contains nav points of the actual page - (nav points are actual handled by this theme throug js *}}
<div id="topbar-second" class="topbar">
<div class="container">
<div class="col-lg-3 col-md-3 hidden-sm hidden-xs"></div>
<div class="col-lg-3 col-md-3 hidden-sm hidden-xs" id="nav-short-info"></div>
<div class="col-lg-7 col-md-7 col-sm-11 col-xs-10" id="tabmenu"></div>
<div class="col-lg-2 col-md-2 col-sm-1 col-xs-2" id="navbar-button"></div>
</div>

View file

@ -20,7 +20,19 @@
</div>
{{* The short information which will appended to the second navbar by scrollspy *}}
<div id="vcard-short-info-wrapper" style="display: none;">
<div id="vcard-short-info" class="media" style="display: none">
<div id="vcard-short-photo-wrapper" class="pull-left">
<img class="media-object" src="{{$profile.photo}}" alt="{{$profile.name}}" />
</div>
<div id="vcard-short-desc" class="media-body">
<h4 class="media-heading">{{$profile.name}}</h4>
{{if $profile.addr}}<div class="vcard-short-addr">{{$profile.addr}}</div>{{/if}}
</div>
</div>
</div>
<div class="panel-body">
<div class="profile-header">

View file

@ -1,4 +1,7 @@
{{* important notes: The frio theme hides under certain conditions some parts of the templates through css.
Some parts of this template will be moved by js to other places (see theme.js) - E.g. the save-search button}}
<div id="{{$id}}" {{* class="input-group" *}}>
<div id="search-wrapper">
<form action="{{$action_url}}" method="get" >
@ -15,7 +18,7 @@
<div class="col-md-8">
{{* The button to save searches *}}
{{if $savedsearch}}
<button class="btn btn-primary btn-small pull-right" type="submit" name="save" id="search-save" value="{{$save_label}}">{{$save_label}}</button>
<button class="btn btn-primary btn-small pull-right" type="submit" name="save" value="{{$save_label}}">{{$save_label}}</button>
{{/if}}
{{* The select popup menu to select what kind of results the user would like to search for *}}
@ -43,4 +46,9 @@
</form>
</div>
{{* This form is inserted as experiment to move the search-save button to the second navbar with js *}}
<form id="search-save-form" action="{{$action_url}}" method="get" >
<input type="hidden" name="search" value="{{$s}}" />
<button class="btn btn-primary btn-sm btn-main pull-right" type="submit" name="save" id="search-save" value="{{$save_label}}"><i class="fa fa-floppy-o fa-2x" aria-hidden="true"></i></button>
</form>
</div>

View file

@ -6,6 +6,20 @@
<div id="profile-photo-wrapper" class="thumbnail"><img class="vcard-photo photo" src="{{$photo}}" alt="{{$name}}" /></div>
{{/if}}
{{* The short information which will appended to the second navbar by scrollspy *}}
<div id="vcard-short-info-wrapper" style="display: none;">
<div id="vcard-short-info" class="media" style="display: none">
<div id="vcard-short-photo-wrapper" class="pull-left">
<img class="media-object" src="{{$photo}}" alt="{{$name}}" />
</div>
<div id="vcard-short-desc" class="media-body">
<h4 class="media-heading">{{$name}}</h4>
{{if $addr}}<div class="vcard-short-addr">{{$addr}}</div>{{/if}}
</div>
</div>
</div>
<div class="panel-body">
<div class="fn">{{$name}}</div>
{{if $addr}}<div class="p-addr">{{$addr}}</div>{{/if}}