From 53fb8b1181b279e234d60e332fd0b52f8bb5e63e Mon Sep 17 00:00:00 2001 From: rabuzarus <> Date: Sat, 11 Jun 2016 01:28:25 +0200 Subject: [PATCH 1/5] frio: a short contact informations will be provided at the second nav bar by scrolling down (on pages where vcard is available) --- view/theme/frio/css/style.css | 45 +++ .../frameworks/jquery-scrollspy/README.md | 183 ++++++++++++ .../frameworks/jquery-scrollspy/bower.json | 18 ++ .../frameworks/jquery-scrollspy/gulpfile.js | 65 +++++ .../jquery-scrollspy/jquery-scrollspy.js | 267 ++++++++++++++++++ .../jquery-scrollspy/jquery-scrollspy.min.js | 1 + .../frameworks/jquery-scrollspy/package.json | 21 ++ view/theme/frio/js/theme.js | 24 ++ view/theme/frio/templates/head.tpl | 1 + view/theme/frio/templates/nav.tpl | 2 +- view/theme/frio/templates/profile_vcard.tpl | 12 + view/theme/frio/templates/vcard-widget.tpl | 14 + 12 files changed, 652 insertions(+), 1 deletion(-) create mode 100644 view/theme/frio/frameworks/jquery-scrollspy/README.md create mode 100644 view/theme/frio/frameworks/jquery-scrollspy/bower.json create mode 100644 view/theme/frio/frameworks/jquery-scrollspy/gulpfile.js create mode 100644 view/theme/frio/frameworks/jquery-scrollspy/jquery-scrollspy.js create mode 100644 view/theme/frio/frameworks/jquery-scrollspy/jquery-scrollspy.min.js create mode 100644 view/theme/frio/frameworks/jquery-scrollspy/package.json diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index 0ecb56441d..591b82462b 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -941,6 +941,51 @@ aside .vcard #dfrn-request-link, aside .vcard #wallmessage-link { width: 100%; } +/* vcard-short-info */ +#vcard-short-info, +#nav-short-info .contact-wrapper { + margin-top: 3px; + height: 40px; + white-space: nowrap; + overflow: hidden; + padding-right: 20px; +} +#vcard-short-photo-wrapper img, +#nav-short-info .contact-wrapper img { + height: 34px; + width: 34px; +} +#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; +} +#nav-short-info .contact-wrapper #contact-entry-url-network { + color: #777; +} +.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 { diff --git a/view/theme/frio/frameworks/jquery-scrollspy/README.md b/view/theme/frio/frameworks/jquery-scrollspy/README.md new file mode 100644 index 0000000000..5707f31fec --- /dev/null +++ b/view/theme/frio/frameworks/jquery-scrollspy/README.md @@ -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 `
` section, e.g.: + +```html + + +``` + +2. Initialise ScrollSpy once the DOM has been loaded: + +```javascript + +``` + +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 +``` diff --git a/view/theme/frio/frameworks/jquery-scrollspy/bower.json b/view/theme/frio/frameworks/jquery-scrollspy/bower.json new file mode 100644 index 0000000000..8257ebdd83 --- /dev/null +++ b/view/theme/frio/frameworks/jquery-scrollspy/bower.json @@ -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": { + } +} diff --git a/view/theme/frio/frameworks/jquery-scrollspy/gulpfile.js b/view/theme/frio/frameworks/jquery-scrollspy/gulpfile.js new file mode 100644 index 0000000000..4c7563c5d7 --- /dev/null +++ b/view/theme/frio/frameworks/jquery-scrollspy/gulpfile.js @@ -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 diff --git a/view/theme/frio/frameworks/jquery-scrollspy/jquery-scrollspy.js b/view/theme/frio/frameworks/jquery-scrollspy/jquery-scrollspy.js new file mode 100644 index 0000000000..4fd4f53a6a --- /dev/null +++ b/view/theme/frio/frameworks/jquery-scrollspy/jquery-scrollspy.js @@ -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)); diff --git a/view/theme/frio/frameworks/jquery-scrollspy/jquery-scrollspy.min.js b/view/theme/frio/frameworks/jquery-scrollspy/jquery-scrollspy.min.js new file mode 100644 index 0000000000..2782536b36 --- /dev/null +++ b/view/theme/frio/frameworks/jquery-scrollspy/jquery-scrollspy.min.js @@ -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); \ No newline at end of file diff --git a/view/theme/frio/frameworks/jquery-scrollspy/package.json b/view/theme/frio/frameworks/jquery-scrollspy/package.json new file mode 100644 index 0000000000..27ca196630 --- /dev/null +++ b/view/theme/frio/frameworks/jquery-scrollspy/package.json @@ -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" + } +} diff --git a/view/theme/frio/js/theme.js b/view/theme/frio/js/theme.js index 9be1b9456e..23c1f096e3 100644 --- a/view/theme/frio/js/theme.js +++ b/view/theme/frio/js/theme.js @@ -120,7 +120,31 @@ $(document).ready(function(){ // initialize the bootstrap-select $('.selectpicker').selectpicker(); + // 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").appendTo("#vcard-short-info-wrapper"); + $("#vcard-short-info").fadeOut(500); + }, + 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 ); diff --git a/view/theme/frio/templates/head.tpl b/view/theme/frio/templates/head.tpl index afdfaa7857..57148736d4 100644 --- a/view/theme/frio/templates/head.tpl +++ b/view/theme/frio/templates/head.tpl @@ -73,6 +73,7 @@ + {{* own js files *}} diff --git a/view/theme/frio/templates/nav.tpl b/view/theme/frio/templates/nav.tpl index b8d5b2307e..78f1024d3e 100644 --- a/view/theme/frio/templates/nav.tpl +++ b/view/theme/frio/templates/nav.tpl @@ -250,7 +250,7 @@ {{* The second navbar which contains nav points of the actual page - (nav points are actual handled by this theme throug js *}} + {{* The short information which will appended to the second navbar by scrollspy *}} +