mirror of
https://github.com/humhub/humhub.git
synced 2025-01-17 22:28:51 +01:00
Major js api enhancements + stream rewrite
This commit is contained in:
parent
c889256aa3
commit
ae65760599
1862
js/dist/humhub.all.js
vendored
1862
js/dist/humhub.all.js
vendored
File diff suppressed because it is too large
Load Diff
1
js/dist/humhub.all.min.js
vendored
1
js/dist/humhub.all.min.js
vendored
File diff suppressed because one or more lines are too long
367
js/humhub/humhub.action.js
Normal file
367
js/humhub/humhub.action.js
Normal file
@ -0,0 +1,367 @@
|
||||
/**
|
||||
* Thid module can be used by humhub sub modules for registering handlers and serves as core module for executing actions triggered in the gui.
|
||||
* A module can either register global handler by using the registerHandler and registerAjaxHandler functions or use the content mechanism.
|
||||
*/
|
||||
humhub.initModule('action', function (module, require, $) {
|
||||
var _handler = {};
|
||||
var object = require('util').object;
|
||||
var string = require('util').string;
|
||||
var client = require('client');
|
||||
var loader = require('ui.loader');
|
||||
|
||||
module.initOnPjaxLoad = false;
|
||||
|
||||
var DATA_COMPONENT = 'action-component';
|
||||
var DATA_COMPONENT_SELECTOR = '[data-' + DATA_COMPONENT + ']';
|
||||
|
||||
var Component = function (container) {
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
this.$ = (object.isString(container)) ? $('#' + container) : container;
|
||||
this.base = this.$.data(DATA_COMPONENT);
|
||||
};
|
||||
|
||||
Component.prototype.data = function (dataSuffix) {
|
||||
var result = this.$.data(dataSuffix);
|
||||
if (!result) {
|
||||
var parentComponent = this.parent();
|
||||
if (parentComponent) {
|
||||
return parentComponent.data(dataSuffix);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
Component.prototype.parent = function () {
|
||||
var $parent = this.$.parent().closest(DATA_COMPONENT_SELECTOR);
|
||||
if ($parent.length) {
|
||||
try {
|
||||
var ParentType = require($parent.data(DATA_COMPONENT));
|
||||
return new ParentType($parent);
|
||||
} catch (err) {
|
||||
console.error('Could not instantiate parent component: ' + $parent.data(DATA_COMPONENT), err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Component.prototype.children = function () {
|
||||
var result = [];
|
||||
this.$.find(DATA_COMPONENT_SELECTOR).each(function () {
|
||||
var component = Component.getInstance($(this));
|
||||
if (component) {
|
||||
result.push(component);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
Component.prototype.hasAction = function (action) {
|
||||
return this.actions().indexOf(action) >= 0;
|
||||
};
|
||||
|
||||
Component.prototype.actions = function () {
|
||||
return [];
|
||||
};
|
||||
|
||||
Component.getInstance = function ($node) {
|
||||
//Determine closest component node (parent or or given node)
|
||||
$node = (object.isString($node)) ? $('#' + $node) : $node;
|
||||
var $componentRoot = ($node.data(DATA_COMPONENT)) ? $node : Component.getClosestComponentNode($node);
|
||||
|
||||
var componentType = $componentRoot.data(DATA_COMPONENT);
|
||||
|
||||
var ComponentType = require(componentType);
|
||||
if (ComponentType) {
|
||||
return new ComponentType($componentRoot);
|
||||
} else {
|
||||
module.log.error('Tried to instantiate component with invalid type: ' + componentType);
|
||||
}
|
||||
};
|
||||
|
||||
Component.getClosestComponentNode = function ($element) {
|
||||
return $element.closest(DATA_COMPONENT_SELECTOR);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the given componentAction event. The event should provide the following properties:
|
||||
*
|
||||
* $trigger (required) : the trigger node of the event
|
||||
* handler (required) : the handler functionn name to be executed on the component
|
||||
* type (optoinal) : the event type 'click', 'change',...
|
||||
*
|
||||
* @param {object} event - event object
|
||||
* @returns {Boolean} true if the componentAction could be executed else false
|
||||
*/
|
||||
Component.handleAction = function (event) {
|
||||
var component = Component.getInstance(event.$trigger);
|
||||
if (component) {
|
||||
//Check if the content instance provides this actionhandler
|
||||
if (event.handler && component[event.handler]) {
|
||||
component[event.handler](event);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor for initializing the module.
|
||||
*/
|
||||
module.init = function () {
|
||||
//Binding default action types
|
||||
this.bindAction(document, 'click', '[data-action-click]');
|
||||
this.bindAction(document, 'dblclick', '[data-action-dblclick]');
|
||||
this.bindAction(document, 'change', '[data-action-mouseout]');
|
||||
|
||||
updateBindings();
|
||||
|
||||
//Add addition for loader buttons
|
||||
require('ui.additions').registerAddition('[data-action-load-button]', function () {
|
||||
var that = this;
|
||||
this.on('click.humhub-action-load-button', function (evt) {
|
||||
if (!that.find('.action-loader').length) {
|
||||
that.append('<span class="action-loader"><i class="fa fa-spinner fa-pulse"></i></span>');
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers a given handler with the given id.
|
||||
*
|
||||
* This handler will be called e.g. after clicking a button with the handler id as
|
||||
* data-action-click attribute.
|
||||
*
|
||||
* The handler can access additional event information through the argument event.
|
||||
* The this object within the handler will be the trigger of the event.
|
||||
*
|
||||
* @param {string} id handler id should contain the module namespace
|
||||
* @param {function} handler function with one event argument
|
||||
* @returns {undefined}
|
||||
*/
|
||||
module.registerHandler = function (id, handler) {
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
_handler[id] = handler;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Registers an ajax eventhandler.
|
||||
* The function can either be called with four arguments (id, successhandler, errorhandler, additional config)
|
||||
* or with two (id, cfg) where tha handlers are contained in the config object itself.
|
||||
*
|
||||
* The successhandler will be called only if the response does not contain any errors or errormessages.
|
||||
* So the errorhandler is called for application and http errors.
|
||||
*
|
||||
* The config can contain additional ajax settings.
|
||||
*
|
||||
* @param {type} id
|
||||
* @param {type} success
|
||||
* @param {type} error
|
||||
* @param {type} cfg
|
||||
* @returns {undefined}
|
||||
*/
|
||||
module.registerAjaxHandler = function (id, success, error, cfg) {
|
||||
cfg = cfg || {};
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (object.isFunction(success)) {
|
||||
cfg.success = success;
|
||||
cfg.error = error;
|
||||
} else {
|
||||
cfg = success;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
_handler[id] = function (event) {
|
||||
var path = $(this).data('action-url-' + event.type) || $(this).data('action-url');
|
||||
client.ajax(path, cfg);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
var actionBindings = [];
|
||||
|
||||
var updateBindings = function () {
|
||||
module.log.debug('Update bindings');
|
||||
$.each(actionBindings, function (i, binding) {
|
||||
var $targets = $(binding.selector);
|
||||
$targets.off(binding.event).on(binding.event, function (evt) {
|
||||
module.log.debug('Handle direct trigger action', evt);
|
||||
return binding.handle(evt, $(this));
|
||||
});
|
||||
$targets.data('action-'+binding.event, true);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* ActionBinding instances are used to store the binding settings and handling
|
||||
* binding events.
|
||||
*
|
||||
* @param {type} cfg
|
||||
* @returns {humhub_action_L5.ActionBinding}
|
||||
*/
|
||||
var ActionBinding = function (cfg) {
|
||||
cfg = cfg || {};
|
||||
this.parent = cfg.parent;
|
||||
this.eventType = cfg.type;
|
||||
this.event = cfg.event;
|
||||
this.selector = cfg.selector;
|
||||
this.directHandler = cfg.directHandler;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles an action event for the given $trigger node.
|
||||
*
|
||||
* This handler searches for a valid handler, by checking the following handler types in the given order:
|
||||
*
|
||||
* - Direct-ActionHandler is called if a directHandler was given when binding the action.
|
||||
* - Component-ActionHandler is called if $trigger is part of a component and the component handler can be resolved
|
||||
* - Global-ActionHandler is called if we find a handler in the _handler array. See registerHandler, registerAjaxHandler
|
||||
* - Namespace-ActionHandler is called if we can resolve an action by namespace e.g: data-action-click="myModule.myAction"
|
||||
*
|
||||
* @param {type} evt the originalEvent
|
||||
* @param {type} $trigger the jQuery node which triggered the event
|
||||
* @returns {undefined}
|
||||
*/
|
||||
ActionBinding.prototype.handle = function (evt, $trigger) {
|
||||
module.log.debug('Handle Action', this);
|
||||
evt.preventDefault();
|
||||
|
||||
var event = this.createActionEvent(evt, $trigger);
|
||||
|
||||
// Search and execute a stand alone handler or try to call the content action handler
|
||||
try {
|
||||
// Check for a direct action handler
|
||||
if (object.isFunction(this.directHandler)) {
|
||||
this.directHandler.apply($trigger, [event]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for a component action handler
|
||||
if (Component.handleAction(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for global registered handlers
|
||||
if (_handler[this.handler]) {
|
||||
_handler[this.handler].apply($trigger, [event]);
|
||||
return;
|
||||
}
|
||||
|
||||
// As last resort we try to call the action by namespace for handlers like humhub.modules.myModule.myAction
|
||||
var splittedNS = this.handler.split('.');
|
||||
var handlerAction = splittedNS[splittedNS.length - 1];
|
||||
var target = require(string.cutsuffix(this.handler, '.' + handlerAction));
|
||||
|
||||
if (object.isFunction(target)) {
|
||||
target[handlerAction](event);
|
||||
} else {
|
||||
module.log.error('actionHandlerNotFound', this, true);
|
||||
}
|
||||
} catch (e) {
|
||||
module.log.error('default', e, true);
|
||||
_removeLoaderFromEventTarget(evt);
|
||||
} finally {
|
||||
// Just to get sure the handler is not called twice.
|
||||
if(evt.originalEvent) {
|
||||
evt.originalEvent.actionHandled = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ActionBinding.prototype.createActionEvent = function (evt, $trigger) {
|
||||
var event = $.Event(this.eventType);
|
||||
event.originalEvent = evt;
|
||||
|
||||
// Add some additional action related data to our event.
|
||||
event.$trigger = $trigger;
|
||||
|
||||
// If the trigger contains an url setting we add it to the event object, and prefer the typed url over the global data-action-url
|
||||
event.url = $trigger.data('action-' + this.eventType + '-url') || $trigger.data('action-url');
|
||||
event.params = $trigger.data('action-' + this.eventType + '-params') || $trigger.data('action-params');
|
||||
|
||||
//Get the handler id, either a stand alone handler or a content handler function e.g: 'edit'
|
||||
event.handler = $trigger.data('action' + '-' + this.eventType);
|
||||
|
||||
if ($trigger.is(':submit')) {
|
||||
event.$form = $trigger.closest('form');
|
||||
}
|
||||
|
||||
event.finish = function () {
|
||||
_removeLoaderFromEventTarget(evt);
|
||||
};
|
||||
|
||||
return event;
|
||||
};
|
||||
|
||||
var _removeLoaderFromEventTarget = function (evt) {
|
||||
if (evt && evt.target) {
|
||||
loader.reset(evt.target);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Binds an delegate wrapper event handler to the parent node. This is used to detect action handlers like
|
||||
* data-action-click events and map the call to either a stand alone handler or a content
|
||||
* action handler. The trigger of a contentAction has to be contained in a data-content-base node.
|
||||
*
|
||||
* This function uses the jQuery event delegation:
|
||||
*
|
||||
* $(parent).on(type, selector, function(){...});
|
||||
*
|
||||
* This assures the event binding for dynamic content (ajax content etc..)
|
||||
*
|
||||
* @see {@link humhub.modules.content.handleAction}
|
||||
* @param {Node|jQuery} parent - the event target
|
||||
* @param {string} type - event type e.g. click, change,...
|
||||
* @param {string} selector - jQuery selector
|
||||
* @param {string} selector - jQuery selector
|
||||
*/
|
||||
module.bindAction = function (parent, type, selector, directHandler) {
|
||||
parent = parent || document;
|
||||
var $parent = parent.jquery ? parent : $(parent);
|
||||
var actionEvent = type + '.humhub-action';
|
||||
|
||||
var actionBinding = new ActionBinding({
|
||||
parent: parent,
|
||||
type: type,
|
||||
event: actionEvent,
|
||||
selector: selector,
|
||||
directHandler: directHandler
|
||||
});
|
||||
|
||||
// Add new ActionBinding with given settings.
|
||||
actionBindings.push(actionBinding);
|
||||
|
||||
$parent.on(actionEvent, selector, function (evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
// Get sure we don't call the handler twice if the event was already handled by trigger.
|
||||
if ($(this).data('action-'+actionBinding.event)
|
||||
|| evt.originalEvent && evt.originalEvent.actionHandled) {
|
||||
return;
|
||||
}
|
||||
|
||||
module.log.debug('Detected unhandled action', actionBinding);
|
||||
updateBindings();
|
||||
actionBinding.handle(evt, $(this));
|
||||
});
|
||||
|
||||
return;
|
||||
};
|
||||
|
||||
module.export({
|
||||
Component: Component
|
||||
});
|
||||
});
|
@ -1,274 +0,0 @@
|
||||
/**
|
||||
* Thid module can be used by humhub sub modules for registering handlers and serves as core module for executing actions triggered in the gui.
|
||||
* A module can either register global handler by using the registerHandler and registerAjaxHandler functions or use the content mechanism.
|
||||
*/
|
||||
humhub.initModule('actions', function (module, require, $) {
|
||||
var _handler = {};
|
||||
var object = require('util').object;
|
||||
var string = require('util').string;
|
||||
var client = require('client');
|
||||
|
||||
var DATA_COMPONENT = 'action-component';
|
||||
var DATA_COMPONENT_SELECTOR = '[data-'+DATA_COMPONENT+']';
|
||||
|
||||
var Component = function(container) {
|
||||
if(!container) {
|
||||
return;
|
||||
}
|
||||
this.$ = (object.isString(container)) ? $('#' + container) : container;
|
||||
this.base = this.$.data(DATA_COMPONENT);
|
||||
};
|
||||
|
||||
Component.prototype.data = function(dataSuffix) {
|
||||
var result = this.$.data(dataSuffix);
|
||||
if(!result) {
|
||||
var parentComponent = this.parent();
|
||||
if(parentComponent) {
|
||||
return parentComponent.data(dataSuffix);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
Component.prototype.parent = function() {
|
||||
var $parent = this.$.parent().closest(DATA_COMPONENT_SELECTOR);
|
||||
if($parent.length) {
|
||||
try {
|
||||
var ParentType = require($parent.data(DATA_COMPONENT));
|
||||
return new ParentType($parent);
|
||||
} catch(err) {
|
||||
console.error('Could not instantiate parent component: '+$parent.data(DATA_COMPONENT));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Component.prototype.children = function() {
|
||||
var result = [];
|
||||
this.$.find(DATA_COMPONENT_SELECTOR).each(function() {
|
||||
var component = Component.getInstance($(this));
|
||||
if(component) {
|
||||
result.push(component);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
Component.prototype.hasAction = function(action) {
|
||||
return this.actions().indexOf(action) >= 0;
|
||||
};
|
||||
|
||||
Component.prototype.actions = function() {
|
||||
return [];
|
||||
};
|
||||
|
||||
Component.getInstance = function($node) {
|
||||
//Determine closest component node (parent or or given node)
|
||||
$node = (object.isString($node)) ? $('#'+$node) : $node;
|
||||
var $componentRoot = ($node.data(DATA_COMPONENT)) ? $node : Component.getClosestComponentNode($node);
|
||||
|
||||
var componentType = $componentRoot.data(DATA_COMPONENT);
|
||||
|
||||
var ComponentType = require(componentType);
|
||||
if(ComponentType) {
|
||||
return new ComponentType($componentRoot);
|
||||
} else {
|
||||
console.error('Tried to instantiate component with invalid type: '+componentType);
|
||||
}
|
||||
};
|
||||
|
||||
Component.getClosestComponentNode = function($element) {
|
||||
return $element.closest(DATA_COMPONENT_SELECTOR);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the given componentAction event. The event should provide the following properties:
|
||||
*
|
||||
* $trigger (required) : the trigger node of the event
|
||||
* handler (required) : the handler functionn name to be executed on the component
|
||||
* type (optoinal) : the event type 'click', 'change',...
|
||||
*
|
||||
* @param {object} event - event object
|
||||
* @returns {Boolean} true if the componentAction could be executed else false
|
||||
*/
|
||||
Component.handleAction = function(event) {
|
||||
var component = Component.getInstance(event.$trigger);
|
||||
if(component) {
|
||||
//Check if the content instance provides this actionhandler
|
||||
if(event.handler && component[event.handler]) {
|
||||
component[event.handler](event);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor for initializing the module.
|
||||
*/
|
||||
module.init = function () {
|
||||
//Binding default action types
|
||||
this.bindAction(document, 'click', '[data-action-click]');
|
||||
this.bindAction(document, 'dblclick', '[data-action-dblclick]');
|
||||
this.bindAction(document, 'change', '[data-action-mouseout]');
|
||||
|
||||
//Add addition for loader buttons
|
||||
require('additions').registerAddition('[data-action-load-button]', function () {
|
||||
var that = this;
|
||||
this.on('click.humhub-action-load-button', function (evt) {
|
||||
if (!that.find('.action-loader').length) {
|
||||
that.append('<span class="action-loader"><i class="fa fa-spinner fa-pulse"></i></span>');
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers a given handler with the given id.
|
||||
*
|
||||
* This handler will be called e.g. after clicking a button with the handler id as
|
||||
* data-action-click attribute.
|
||||
*
|
||||
* The handler can access additional event information through the argument event.
|
||||
* The this object within the handler will be the trigger of the event.
|
||||
*
|
||||
* @param {string} id handler id should contain the module namespace
|
||||
* @param {function} handler function with one event argument
|
||||
* @returns {undefined}
|
||||
*/
|
||||
module.registerHandler = function (id, handler) {
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (handler) {
|
||||
_handler[id] = handler;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers an ajax eventhandler.
|
||||
* The function can either be called with four arguments (id, successhandler, errorhandler, additional config)
|
||||
* or with two (id, cfg) where tha handlers are contained in the config object itself.
|
||||
*
|
||||
* The successhandler will be called only if the response does not contain any errors or errormessages.
|
||||
* So the errorhandler is called for application and http errors.
|
||||
*
|
||||
* The config can contain additional ajax settings.
|
||||
*
|
||||
* @param {type} id
|
||||
* @param {type} success
|
||||
* @param {type} error
|
||||
* @param {type} cfg
|
||||
* @returns {undefined}
|
||||
*/
|
||||
module.registerAjaxHandler = function (id, success, error, cfg) {
|
||||
cfg = cfg || {};
|
||||
if (!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (object.isFunction(success)) {
|
||||
cfg.success = success;
|
||||
cfg.error = error;
|
||||
} else {
|
||||
cfg = success;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
_handler[id] = function (event) {
|
||||
var path = $(this).data('action-url-' + event.type) || $(this).data('action-url');
|
||||
client.ajax(path, cfg);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Binds an delegate wrapper event handler to the parent node. This is used to detect action handlers like
|
||||
* data-action-click events and map the call to either a stand alone handler or a content
|
||||
* action handler. The trigger of a contentAction has to be contained in a data-content-base node.
|
||||
*
|
||||
* This function uses the jQuery event delegation:
|
||||
*
|
||||
* $(parent).on(type, selector, function(){...});
|
||||
*
|
||||
* This assures the event binding for dynamic content (ajax content etc..)
|
||||
*
|
||||
* @see {@link humhub.modules.content.handleAction}
|
||||
* @param {Node|jQuery} parent - the event target
|
||||
* @param {string} type - event type e.g. click, change,...
|
||||
* @param {string} selector - jQuery selector
|
||||
* @param {string} selector - jQuery selector
|
||||
*/
|
||||
module.bindAction = function (parent, type, selector, directHandler) {
|
||||
parent = parent || document;
|
||||
var $parent = parent.jquery ? parent : $(parent);
|
||||
$parent.on(type+'.humhub-action', selector, function (evt) {
|
||||
evt.preventDefault();
|
||||
//The element which triggered the action e.g. a button or link
|
||||
$trigger = $(this);
|
||||
|
||||
//Get the handler id, either a stand alone handler or a content handler function e.g: 'edit'
|
||||
var handlerId = $trigger.data('action' + '-' + type);
|
||||
var event = {type: type, $trigger: $trigger, handler: handlerId};
|
||||
|
||||
event.finish = function() {
|
||||
_removeLoaderFromEventTarget(evt);
|
||||
};
|
||||
|
||||
//TODO: handle with $.Event
|
||||
//var event = $.Event(type, {$trigger: $trigger});
|
||||
//event.originalEvent = evt;
|
||||
|
||||
//Search and execute a stand alone handler or try to call the content action handler
|
||||
try {
|
||||
//Direct action handler
|
||||
if(object.isFunction(directHandler)) {
|
||||
directHandler.apply($trigger, [event]);
|
||||
return;
|
||||
}
|
||||
|
||||
//Component handler
|
||||
if(Component.handleAction(event)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Registered handler
|
||||
if(_handler[handlerId]) {
|
||||
//Registered action handler
|
||||
var handler = _handler[handlerId];
|
||||
handler.apply($trigger, [event]);
|
||||
return;
|
||||
}
|
||||
|
||||
//As last resort we try to call the action by namespace handler
|
||||
var splittedNS = handlerId.split('.');
|
||||
var handler = splittedNS[splittedNS.length - 1];
|
||||
var target = require(string.cutsuffix(handlerId, '.' + handler));
|
||||
if(object.isFunction(target)) {
|
||||
target[handler]({type: type, $trigger: $trigger});
|
||||
} else {
|
||||
console.error('Could not determine actionhandler for: '+handlerId);
|
||||
}
|
||||
} catch (e) {
|
||||
//TODO: handle error !
|
||||
console.error('Error while handling action event for handler "' + handlerId+'"', e);
|
||||
_removeLoaderFromEventTarget(evt);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var _removeLoaderFromEventTarget = function (evt) {
|
||||
if (evt.target) {
|
||||
$target = $(evt.target);
|
||||
$loader = $target.find('.action-loader');
|
||||
|
||||
if ($loader.length) {
|
||||
$loader.remove();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
module.export({
|
||||
Component: Component
|
||||
});
|
||||
});
|
@ -5,32 +5,17 @@
|
||||
humhub.initModule('client', function (module, require, $) {
|
||||
var object = require('util').object;
|
||||
|
||||
var init = function () {
|
||||
/*$.ajaxPrefilter('html', function(options, originalOptions, jqXHR) {
|
||||
debugger;
|
||||
console.log(options);
|
||||
var pjaxHandler = options.success;
|
||||
options.success = function(result, textStatus, xhr) {
|
||||
console.log(result);
|
||||
pjaxHandler(result, textStatus, xhr);
|
||||
};
|
||||
options.error = function(err) {
|
||||
debugger;
|
||||
};
|
||||
});
|
||||
|
||||
$.pjax.defaults.maxCacheLength = 0;
|
||||
$('a.dashboard').on('click', function(evt) {
|
||||
debugger;
|
||||
evt.preventDefault();
|
||||
$.pjax({url:$(this).attr('href'), container: '#main-content', maxCacheLength:0, timeout:2000});
|
||||
});*/
|
||||
}
|
||||
/**
|
||||
* Response Wrapper Object for easily accessing common data
|
||||
*/
|
||||
var Response = function (data) {
|
||||
$.extend(this, data);
|
||||
var Response = function (data, dataType) {
|
||||
if(!dataType || dataType === 'json') {
|
||||
$.extend(this, data);
|
||||
} else if(dataType) {
|
||||
this[dataType] = data;
|
||||
} else {
|
||||
this.data = data;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@ -88,7 +73,8 @@ humhub.initModule('client', function (module, require, $) {
|
||||
$form = object.isString($form) ? $($form) : $form;
|
||||
cfg.type = $form.attr('method') || 'post';
|
||||
cfg.data = $form.serialize();
|
||||
ajax($form.attr('action'), cfg);
|
||||
var url = cfg['url'] || $form.attr('action');
|
||||
return ajax(url, cfg);
|
||||
};
|
||||
|
||||
var post = function (path, cfg) {
|
||||
@ -97,28 +83,39 @@ humhub.initModule('client', function (module, require, $) {
|
||||
cfg.method = 'POST';
|
||||
return ajax(path, cfg);
|
||||
};
|
||||
|
||||
var get = function (path, cfg) {
|
||||
var cfg = cfg || {};
|
||||
cfg.type = 'GET';
|
||||
cfg.method = 'GET';
|
||||
return ajax(path, cfg);
|
||||
};
|
||||
|
||||
var ajax = function (path, cfg) {
|
||||
if(object.isFunction(cfg)) {
|
||||
cfg = {'success' : cfg};
|
||||
}
|
||||
|
||||
var promise = new Promise(function (resolve, reject) {
|
||||
cfg = cfg || {};
|
||||
|
||||
//Wrap the actual error handler with our own and call
|
||||
var errorHandler = cfg.error;
|
||||
var error = function (xhr, textStatus, errorThrown, data, status) {
|
||||
var error = function (xhr, textStatus, errorThrown, data) {
|
||||
//Textstatus = "timeout", "error", "abort", "parsererror", "application"
|
||||
if (errorHandler && object.isFunction(errorHandler)) {
|
||||
var response = new Response();
|
||||
response.setAjaxError(xhr, errorThrown, textStatus, data, status);
|
||||
response.setAjaxError(xhr, errorThrown, textStatus, data, xhr.status);
|
||||
errorHandler(response);
|
||||
}
|
||||
reject(xhr, textStatus, errorThrown, data, status);
|
||||
reject({'textStatus': textStatus, 'response': xhr.responseJSON, 'error': errorThrown, 'data': data, 'status': xhr.status});
|
||||
};
|
||||
|
||||
var successHandler = cfg.success;
|
||||
var success = function (json, textStatus, xhr) {
|
||||
var response = new Response(json);
|
||||
var success = function (data, textStatus, xhr) {
|
||||
var response = new Response(data, cfg.dataType);
|
||||
if (response.isError()) { //Application errors
|
||||
return error(xhr, "application", response.getErrors(), json, response.getStatus());
|
||||
return error(xhr, "application", response.getErrors(), data, response.getStatus());
|
||||
} else if (successHandler) {
|
||||
response.textStatus = textStatus;
|
||||
response.xhr = xhr;
|
||||
@ -129,7 +126,7 @@ humhub.initModule('client', function (module, require, $) {
|
||||
|
||||
promise.then(function() {
|
||||
// If content with <link> tags are inserted in resolve, the ajaxComplete handler in yii.js
|
||||
// makes shure redundant stylesheets are removed.
|
||||
// makes sure redundant stylesheets are removed. Here we get sure it is called after inserting the response.
|
||||
$(document).trigger('ajaxComplete');
|
||||
});
|
||||
|
||||
@ -152,8 +149,8 @@ humhub.initModule('client', function (module, require, $) {
|
||||
module.export({
|
||||
ajax: ajax,
|
||||
post: post,
|
||||
submit: submit,
|
||||
init: init
|
||||
get: get,
|
||||
submit: submit
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
humhub.initModule('client.pjax', function (module, require, $) {
|
||||
var object = require('util').object;
|
||||
var event = require('event');
|
||||
|
||||
module.initOnPjaxLoad = false;
|
||||
|
||||
var init = function () {
|
||||
pjaxRedirectFix();
|
||||
installLoader();
|
||||
}
|
||||
module.installLoader();
|
||||
};
|
||||
|
||||
var pjaxRedirectFix = function () {
|
||||
var pjaxXhr;
|
||||
@ -18,8 +20,18 @@ humhub.initModule('client.pjax', function (module, require, $) {
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("pjax:success", function (evt, data, status, xhr, options) {
|
||||
event.trigger('humhub:modules:client:pjax:afterPageLoad', {
|
||||
'originalEvent': evt,
|
||||
'data': data,
|
||||
'status': status,
|
||||
'xhr': xhr,
|
||||
'options': options
|
||||
});
|
||||
});
|
||||
|
||||
$.ajaxPrefilter('html', function (options, originalOptions, jqXHR) {
|
||||
orgErrorHandler = options.error;
|
||||
var orgErrorHandler = options.error;
|
||||
options.error = function (xhr, textStatus, errorThrown) {
|
||||
var redirect = (xhr.status >= 301 && xhr.status <= 303)
|
||||
if (redirect && xhr.getResponseHeader('X-PJAX-REDIRECT-URL') != "") {
|
||||
@ -31,19 +43,20 @@ humhub.initModule('client.pjax', function (module, require, $) {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var installLoader = function () {
|
||||
NProgress.configure({showSpinner: false});
|
||||
NProgress.configure({template: '<div class="bar" role="bar"></div>'});
|
||||
|
||||
jQuery(document).on('pjax:start', function () {
|
||||
$(document).on('pjax:start', function () {
|
||||
NProgress.start();
|
||||
});
|
||||
jQuery(document).on('pjax:end', function () {
|
||||
|
||||
$(document).on('pjax:end', function () {
|
||||
NProgress.done();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.export({
|
||||
init: init,
|
||||
|
@ -13,6 +13,12 @@ var humhub = humhub || (function($) {
|
||||
*/
|
||||
var modules = {};
|
||||
|
||||
/**
|
||||
* Flat array with all registered modules.
|
||||
* @type Array
|
||||
*/
|
||||
var moduleArr = [];
|
||||
|
||||
/**
|
||||
* Used to collect modules added while initial page load.
|
||||
* These modules will be intitialized after the document is ready.
|
||||
@ -20,6 +26,13 @@ var humhub = humhub || (function($) {
|
||||
*/
|
||||
var initialModules = [];
|
||||
|
||||
/**
|
||||
* Contains all modules which needs to be reinitialized after a pjax reload
|
||||
* @type Array
|
||||
*/
|
||||
var pjaxInitModules = [];
|
||||
|
||||
|
||||
/**
|
||||
* Is set wehen document is ready
|
||||
* @type Boolean
|
||||
@ -27,7 +40,8 @@ var humhub = humhub || (function($) {
|
||||
var initialized = false;
|
||||
|
||||
/**
|
||||
* Adds an module to the namespace. And initializes either after dom is ready.
|
||||
* Adds a module to the namespace. And initializes after dom is ready.
|
||||
*
|
||||
* The id can be provided either as
|
||||
*
|
||||
* - full namespace humhub.modules.ui.modal
|
||||
@ -81,6 +95,14 @@ var humhub = humhub || (function($) {
|
||||
var instance = resolveNameSpace(id, true);
|
||||
instance.id = 'humhub.modules.'+_cutModulePrefix(id);
|
||||
instance.require = require;
|
||||
instance.initOnPjaxLoad = true;
|
||||
instance.config = require('config').module(instance);
|
||||
instance.isModule = true;
|
||||
|
||||
instance.text = function($key) {
|
||||
return instance.config['text'][$key];
|
||||
};
|
||||
|
||||
instance.export = function(exports) {
|
||||
$.extend(instance, exports);
|
||||
};
|
||||
@ -92,10 +114,17 @@ var humhub = humhub || (function($) {
|
||||
console.error('Error while creating module: '+id, err);
|
||||
}
|
||||
|
||||
moduleArr.push(instance);
|
||||
|
||||
if(instance.init && instance.initOnPjaxLoad) {
|
||||
pjaxInitModules.push(instance);
|
||||
}
|
||||
|
||||
//Initialize the module when document is ready
|
||||
if(!initialized) {
|
||||
initialModules.push(instance);
|
||||
} else {
|
||||
addModuleLogger(instance);
|
||||
instance.init();
|
||||
}
|
||||
};
|
||||
@ -148,25 +177,29 @@ var humhub = humhub || (function($) {
|
||||
});
|
||||
return result;
|
||||
} catch(e) {
|
||||
//TODO: handle could not resolve type/namespace error
|
||||
return;
|
||||
var log = require('log') || console;
|
||||
log.error('Error while resolving namespace: '+typePathe, e);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
/**
|
||||
* Config implementation
|
||||
*/
|
||||
|
||||
var config = {
|
||||
var config = modules['config'] = {
|
||||
id : 'config',
|
||||
|
||||
get : function(module, key, defaultVal) {
|
||||
if(arguments.length === 1) {
|
||||
return this.getModuleConfig(module);
|
||||
return this.module(module);
|
||||
} else if(_isDefined(key)) {
|
||||
var result = this.getModuleConfig(module)[key];
|
||||
var result = this.module(module)[key];
|
||||
return (_isDefined(result)) ? result : defaultVal;
|
||||
}
|
||||
},
|
||||
getModuleConfig: function(module) {
|
||||
|
||||
module: function(module) {
|
||||
module = (module.id) ? module.id : module;
|
||||
module = _cutModulePrefix(module);
|
||||
if(!this[module]) {
|
||||
this[module] = {};
|
||||
}
|
||||
@ -185,13 +218,29 @@ var humhub = humhub || (function($) {
|
||||
that.set(moduleKey, config);
|
||||
});
|
||||
}else if(arguments.length === 2) {
|
||||
$.extend(this.getModuleConfig(moduleId), key);
|
||||
$.extend(this.module(moduleId), key);
|
||||
} else if(arguments.length === 3) {
|
||||
this.getModuleConfig(moduleId)[key] = value;
|
||||
this.module(moduleId)[key] = value;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var event = modules['event'] = {
|
||||
events : $({}),
|
||||
on : function(event, selector, data, handler) {
|
||||
this.events.on(event , selector, data, handler);
|
||||
return this;
|
||||
},
|
||||
trigger : function(eventType, extraParameters) {
|
||||
this.events.trigger(eventType, extraParameters);
|
||||
return this;
|
||||
},
|
||||
one : function(event, selector, data, handler) {
|
||||
this.events.one(event , selector, data, handler);
|
||||
return this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cuts the prefix humub.modules or modules. from the given value.
|
||||
* @param {type} value
|
||||
@ -233,18 +282,43 @@ var humhub = humhub || (function($) {
|
||||
return typeof obj !== 'undefined';
|
||||
};
|
||||
|
||||
var addModuleLogger = function(module, log) {
|
||||
log = log || require('log');
|
||||
module.log = log.module(module);
|
||||
}
|
||||
|
||||
//Initialize all initial modules
|
||||
$(document).ready(function() {
|
||||
var log = require('log');
|
||||
|
||||
$.each(moduleArr, function(i, module) {
|
||||
addModuleLogger(module, log);
|
||||
});
|
||||
|
||||
$.each(initialModules, function(i, module) {
|
||||
event.trigger('humhub:beforeInitModule', module);
|
||||
if(module.init) {
|
||||
try {
|
||||
event.trigger(module.id)
|
||||
module.init();
|
||||
} catch(err) {
|
||||
console.error('Could not initialize module: '+module.id, err);
|
||||
log.error('Could not initialize module: '+module.id, err);
|
||||
}
|
||||
}
|
||||
initialized = true;
|
||||
console.log('Module initialized: '+module.id);
|
||||
event.trigger('humhub:afterInitModule', module);
|
||||
log.debug('Module initialized: '+module.id);
|
||||
});
|
||||
|
||||
event.trigger('humhub:afterInit');
|
||||
|
||||
initialized = true;
|
||||
});
|
||||
|
||||
event.on('humhub:modules:client:pjax:afterPageLoad', function (evt) {
|
||||
$.each(pjaxInitModules, function(i, module) {
|
||||
if(module.initOnPjaxLoad) {
|
||||
module.init();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@ -253,6 +327,7 @@ var humhub = humhub || (function($) {
|
||||
return {
|
||||
initModule: initModule,
|
||||
modules: modules,
|
||||
config: config
|
||||
config: config,
|
||||
event: event,
|
||||
};
|
||||
})($);
|
@ -1,331 +0,0 @@
|
||||
var humhub = humhub || {};
|
||||
|
||||
humhub.util = (function(module, $) {
|
||||
module.object = {
|
||||
isFunction: function(obj) {
|
||||
return Object.prototype.toString.call(obj) === '[object Function]';
|
||||
},
|
||||
|
||||
isObject: function(obj) {
|
||||
return $.isPlainObject(obj);
|
||||
},
|
||||
|
||||
isJQuery: function(obj) {
|
||||
return obj.jquery;
|
||||
},
|
||||
|
||||
isString: function(obj) {
|
||||
return typeof obj === 'string';
|
||||
},
|
||||
|
||||
isNumber: function(n) {
|
||||
return !isNaN(parseFloat(n)) && isFinite(n);
|
||||
},
|
||||
|
||||
isBoolean: function(obj) {
|
||||
return typeof obj === 'boolean';
|
||||
},
|
||||
|
||||
isDefined: function(obj) {
|
||||
if(arguments.length > 1) {
|
||||
var result = true;
|
||||
var that = this;
|
||||
this.each(arguments, function(index, value) {
|
||||
if(!that.isDefined(value)) {
|
||||
result = false;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
return typeof obj !== 'undefined';
|
||||
}
|
||||
};
|
||||
return module;
|
||||
})(humhub.util || {}, $);
|
||||
|
||||
humhub.modules = (function(module, $) {
|
||||
var _handler = {};
|
||||
var _errorHandler = {};
|
||||
var object = humhub.util.object;
|
||||
|
||||
var DATA_ACTION = 'action';
|
||||
|
||||
module.registerHandler = function(id, handler) {
|
||||
if(!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(handler) {
|
||||
_handler[id] = handler;
|
||||
}
|
||||
};
|
||||
|
||||
module.registerAjaxHandler = function(id, success, error, cfg) {
|
||||
debugger;
|
||||
cfg = cfg || {};
|
||||
if(!id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(object.isFunction(success)) {
|
||||
cfg.success = success;
|
||||
cfg.error = error;
|
||||
} else {
|
||||
cfg = success;
|
||||
}
|
||||
|
||||
if(success) {
|
||||
var that = this;
|
||||
_handler[id] = function(event) {
|
||||
var path = $(this).data('url-'+event.type) || $(this).data('url');
|
||||
that.ajax(path, cfg, event);
|
||||
};
|
||||
}
|
||||
|
||||
if(error) {
|
||||
_errorHandler[id] = success;
|
||||
}
|
||||
};
|
||||
|
||||
module.bindAction = function(parent, type, selector) {
|
||||
parent = parent || document;
|
||||
var $parent = parent.jquery ? parent : $(parent);
|
||||
$parent.on(type, selector, function(evt) {
|
||||
evt.preventDefault();
|
||||
//The element which triggered the action e.g. a button or link
|
||||
$trigger = $(this);
|
||||
var handlerId = $trigger.data(DATA_ACTION+'-'+type);
|
||||
var handler = _handler[handlerId];
|
||||
var event = {type:type, $trigger:$trigger};
|
||||
handler.apply($trigger, [event]);
|
||||
});
|
||||
};
|
||||
|
||||
module.bindAction(document, 'click', '[data-action-click]');
|
||||
|
||||
/**
|
||||
* Response Wrapper Object for
|
||||
* easily accessing common data
|
||||
*/
|
||||
var Response = function(data) {
|
||||
this.data = data;
|
||||
};
|
||||
|
||||
Response.prototype.isConfirmation = function() {
|
||||
return this.data && (this.data.status === 0);
|
||||
};
|
||||
|
||||
Response.prototype.isError = function() {
|
||||
return this.data && this.data.status && (this.data.status > 0);
|
||||
};
|
||||
|
||||
Response.prototype.getErrors = function() {
|
||||
return this.data.errors;
|
||||
};
|
||||
|
||||
Response.prototype.getErrorCode = function() {
|
||||
return this.data.errorCode;
|
||||
};
|
||||
|
||||
Response.prototype.toString = function() {
|
||||
return "{ status: "+this.data.status+" error: "+this.data.error+" data: "+this.data.data+" }";
|
||||
};
|
||||
|
||||
var errorHandler = function(cfg, xhr,type,errorThrown, errorCode, path) {
|
||||
errorCode = (xhr) ? xhr.status : parseInt(errorCode);
|
||||
console.warn("AjaxError: "+type+" "+errorThrown+" - "+errorCode);
|
||||
|
||||
if(cfg.error && object.isFunction(cfg.error)) {
|
||||
// "timeout", "error", "abort", "parsererror" or "application"
|
||||
//TODO: den trigger als this verwenden
|
||||
cfg.error(errorThrown, errorCode, type);
|
||||
} else {
|
||||
console.warn('Unhandled ajax error: '+path+" type"+type+" error: "+errorThrown);
|
||||
}
|
||||
};
|
||||
|
||||
module.ajax = function(path, cfg) {
|
||||
var cfg = cfg || {};
|
||||
var async = cfg.async || true;
|
||||
var dataType = cfg.dataType || "json";
|
||||
|
||||
var error = function(xhr,type,errorThrown, errorCode) {
|
||||
errorHandler(cfg, xhr,type,errorThrown, errorCode, path);
|
||||
};
|
||||
|
||||
var success = function(response) {
|
||||
var responseWrapper = new Response(response);
|
||||
|
||||
if(responseWrapper.isError()) { //Application errors
|
||||
return error(undefined,"application",responseWrapper.getError(), responseWrapper.getErrorCode());
|
||||
} else if(cfg.success) {
|
||||
cfg.success(responseWrapper);
|
||||
}
|
||||
};
|
||||
|
||||
$.ajax({
|
||||
url: path,
|
||||
//crossDomain: true, //TODO: read from config
|
||||
type : cfg.type,
|
||||
processData : cfg.processData,
|
||||
contentType: cfg.contentType,
|
||||
async : async,
|
||||
dataType: dataType,
|
||||
success: success,
|
||||
error: error
|
||||
});
|
||||
};
|
||||
|
||||
return module;
|
||||
})(humhub.modules || {}, $);
|
||||
|
||||
humhub.modules.stream = (function(module, $) {
|
||||
|
||||
var ENTRY_ID_SELECTOR_PREFIX = '#wallEntry_';
|
||||
var WALLSTREAM_ID = 'wallStream';
|
||||
|
||||
module.Entry = function(id) {
|
||||
if(typeof id === 'string') {
|
||||
this.id = id;
|
||||
this.$ = $('#'+id);
|
||||
} else if(id.jquery) {
|
||||
this.$ = id;
|
||||
this.id = this.$.attr('id');
|
||||
}
|
||||
};
|
||||
|
||||
module.Entry.prototype.remove = function() {
|
||||
this.$.remove();
|
||||
};
|
||||
|
||||
module.Entry.prototype.highlightContent = function() {
|
||||
var $content = this.getContent();
|
||||
$content.addClass('highlight');
|
||||
$content.delay(200).animate({backgroundColor: 'transparent'}, 1000, function() {
|
||||
$content.removeClass('highlight');
|
||||
$content.css('backgroundColor', '');
|
||||
});
|
||||
};
|
||||
|
||||
module.Entry.prototype.getContent = function() {
|
||||
return this.$.find('.content');
|
||||
};
|
||||
|
||||
module.Stream = function(id) {
|
||||
this.id = id;
|
||||
this.$ = $('#'+id);
|
||||
};
|
||||
|
||||
module.Stream.prototype.getEntry = function(id) {
|
||||
return new module.Entry(this.$.find(ENTRY_ID_SELECTOR_PREFIX+id));
|
||||
};
|
||||
|
||||
module.Stream.prototype.wallStick = function(url) {
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
type: 'post',
|
||||
url: url
|
||||
}).done(function (data) {
|
||||
if (data.success) {
|
||||
if (currentStream) {
|
||||
$.each(data.wallEntryIds, function (k, wallEntryId) {
|
||||
currentStream.deleteEntry(wallEntryId);
|
||||
currentStream.prependEntry(wallEntryId);
|
||||
});
|
||||
$('html, body').animate({scrollTop: 0}, 'slow');
|
||||
}
|
||||
} else {
|
||||
alert(data.errorMessage);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.Stream.prototype.wallUnstick = function(url) {
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
type: 'post',
|
||||
url: url
|
||||
}).done(function (data) {
|
||||
if (data.success) {
|
||||
//Reload the whole stream, since we have to reorder the entries
|
||||
currentStream.showStream();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Click Handler for Archive Link of Wall Posts
|
||||
* (archiveLink.php)
|
||||
*
|
||||
* @param {type} className
|
||||
* @param {type} id
|
||||
*/
|
||||
module.Stream.prototype.wallArchive = function(id) {
|
||||
|
||||
url = wallArchiveLinkUrl.replace('-id-', id);
|
||||
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
type: 'post',
|
||||
url: url
|
||||
}).done(function (data) {
|
||||
if (data.success) {
|
||||
if (currentStream) {
|
||||
$.each(data.wallEntryIds, function (k, wallEntryId) {
|
||||
//currentStream.reloadWallEntry(wallEntryId);
|
||||
// fade out post
|
||||
setInterval(fadeOut(), 1000);
|
||||
|
||||
function fadeOut() {
|
||||
// fade out current archived post
|
||||
$('#wallEntry_' + wallEntryId).fadeOut('slow');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Click Handler for Un Archive Link of Wall Posts
|
||||
* (archiveLink.php)
|
||||
*
|
||||
* @param {type} className
|
||||
* @param {type} id
|
||||
*/
|
||||
module.Stream.prototype.wallUnarchive = function(id) {
|
||||
url = wallUnarchiveLinkUrl.replace('-id-', id);
|
||||
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
type: 'post',
|
||||
url: url
|
||||
}).done(function (data) {
|
||||
if (data.success) {
|
||||
if (currentStream) {
|
||||
$.each(data.wallEntryIds, function (k, wallEntryId) {
|
||||
currentStream.reloadWallEntry(wallEntryId);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
module.getStream = function() {
|
||||
if(!module.mainStream) {
|
||||
module.mainStream = new module.Stream(WALLSTREAM_ID);
|
||||
}
|
||||
return module.mainStream;
|
||||
};
|
||||
|
||||
module.getEntry = function(id) {
|
||||
return module.getStream().getEntry(id);
|
||||
};
|
||||
|
||||
return module;
|
||||
})(humhub.core || {}, $);
|
230
js/humhub/humhub.log.js
Normal file
230
js/humhub/humhub.log.js
Normal file
@ -0,0 +1,230 @@
|
||||
/**
|
||||
*
|
||||
* @param {type} param1
|
||||
* @param {type} param2
|
||||
*/
|
||||
humhub.initModule('log', function (module, require, $) {
|
||||
|
||||
var event = require('event');
|
||||
|
||||
var TRACE_TRACE = 0;
|
||||
var TRACE_DEBUG = 1;
|
||||
var TRACE_INFO = 2;
|
||||
var TRACE_SUCCESS = 3;
|
||||
var TRACE_WARN = 4;
|
||||
var TRACE_ERROR = 5;
|
||||
var TRACE_FATAL = 6;
|
||||
var TRACE_OFF = 7;
|
||||
|
||||
var traceLevels = ['TRACE', 'DEBUG', 'INFO', 'SUCCESS', 'WARN', 'ERROR', 'FATAL', 'OFF'];
|
||||
var config = require('config').module(module);
|
||||
var object = require('util').object;
|
||||
|
||||
var logger = {};
|
||||
|
||||
var Logger = function (module) {
|
||||
if(object.isString(module)) {
|
||||
this.module = require('module');
|
||||
this.moduleId = module;
|
||||
} else if(module){
|
||||
this.module = module;
|
||||
this.moduleId = module.id;
|
||||
}
|
||||
this.update();
|
||||
};
|
||||
|
||||
Logger.prototype.update = function () {
|
||||
var result;
|
||||
if (this.moduleId) {
|
||||
var moduleConfig = require('config').module(this.moduleId);
|
||||
if (moduleConfig.traceLevel && traceLevels.indexOf(moduleConfig.traceLevel.toUpperCase()) >= 0) {
|
||||
result = traceLevels.indexOf(moduleConfig.traceLevel.toUpperCase());
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
result = config.traceLevel || TRACE_INFO;
|
||||
}
|
||||
|
||||
return this.traceLevel = result;
|
||||
};
|
||||
|
||||
Logger.prototype.trace = function (msg,details, setStatus) {
|
||||
this._log(msg, details, setStatus, TRACE_TRACE);
|
||||
};
|
||||
|
||||
Logger.prototype.debug = function (msg, details, setStatus) {
|
||||
this._log(msg, details, setStatus, TRACE_DEBUG);
|
||||
};
|
||||
|
||||
Logger.prototype.info = function (msg, details, setStatus) {
|
||||
this._log(msg, details, setStatus, TRACE_INFO);
|
||||
};
|
||||
|
||||
Logger.prototype.success = function (msg, setStatus) {
|
||||
setStatus = object.isDefined(setStatus) ? setStatus : true;
|
||||
this._log(msg, undefined, setStatus, TRACE_SUCCESS);
|
||||
};
|
||||
|
||||
Logger.prototype.warn = function (msg, error, setStatus) {
|
||||
this._log(msg, error, setStatus, TRACE_WARN);
|
||||
};
|
||||
|
||||
Logger.prototype.error = function (msg, error, setStatus) {
|
||||
this._log(msg, error, setStatus, TRACE_ERROR);
|
||||
};
|
||||
|
||||
Logger.prototype.fatal = function (msg, error, setStatus) {
|
||||
this._log(msg, error, setStatus, TRACE_FATAL);
|
||||
};
|
||||
|
||||
Logger.prototype._log = function (msg, details, setStatus, level) {
|
||||
try {
|
||||
if (object.isBoolean(details)) {
|
||||
setStatus = details;
|
||||
details = undefined;
|
||||
}
|
||||
|
||||
if(msg instanceof Error && level >= TRACE_WARN) {
|
||||
details = msg;
|
||||
msg = this.getMessage(details.message, true);
|
||||
} else if(object.isObject(msg) && msg.status && level >= TRACE_WARN) {
|
||||
details = msg;
|
||||
msg = this.getMessage(msg.status, true);
|
||||
} else if(!object.isObject(msg)) {
|
||||
msg = this.getMessage(msg, (!object.isDefined(msg) && level >= TRACE_WARN));
|
||||
}
|
||||
|
||||
if (this.traceLevel > level) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._consoleLog(msg, level, details);
|
||||
|
||||
if (setStatus) {
|
||||
event.trigger('humhub:modules:log:setStatus', [msg, details, level]);
|
||||
}
|
||||
} catch(e) {
|
||||
console.error('Error while generating log', e);
|
||||
}
|
||||
};
|
||||
|
||||
Logger.prototype.getMessage = function (key, returnDefault) {
|
||||
if(!object.isString(key)) {
|
||||
return key;
|
||||
}
|
||||
|
||||
var result;
|
||||
|
||||
if(this.module) {
|
||||
result = this.module.text(key);
|
||||
}
|
||||
|
||||
if(!result) {
|
||||
result = module.text(key);
|
||||
}
|
||||
|
||||
if(!result && returnDefault) {
|
||||
result = module.text('default.error');
|
||||
} else if(!result){
|
||||
result = key;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
Logger.prototype._consoleLog = function (msg, level, details) {
|
||||
if (window.console) {
|
||||
var consoleMsg = this.moduleId || 'root';
|
||||
consoleMsg += '(' + traceLevels[level] + '): ' + msg;
|
||||
switch (level) {
|
||||
case TRACE_ERROR:
|
||||
case TRACE_FATAL:
|
||||
console.error(consoleMsg, details);
|
||||
break;
|
||||
case TRACE_WARN:
|
||||
if (details) {
|
||||
console.warn(consoleMsg, details);
|
||||
} else {
|
||||
console.warn(consoleMsg);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (details) {
|
||||
console.log(consoleMsg, details);
|
||||
} else {
|
||||
console.log(consoleMsg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var init = function () {
|
||||
module.rootLogger = new Logger();
|
||||
};
|
||||
|
||||
var getRootLogger = function () {
|
||||
if (!module.rootLogger) {
|
||||
module.rootLogger = new Logger();
|
||||
}
|
||||
return module.rootLogger;
|
||||
};
|
||||
|
||||
var getModuleLogger = function (module) {
|
||||
var moduleId = (object.isString(module)) ? module : module.id;
|
||||
if (!logger[moduleId]) {
|
||||
logger[moduleId] = new Logger(module);
|
||||
}
|
||||
return logger[moduleId];
|
||||
};
|
||||
|
||||
var trace = function (msg, details, setStatus) {
|
||||
module.getRootLogger().trace(msg, details, setStatus);
|
||||
};
|
||||
|
||||
var debug = function (msg, details, setStatus) {
|
||||
module.getRootLogger().debug(msg, details, setStatus);
|
||||
};
|
||||
|
||||
var success = function (msg, details, setStatus) {
|
||||
module.getRootLogger().success(msg, details, setStatus);
|
||||
};
|
||||
|
||||
var info = function (msg, details, setStatus) {
|
||||
module.getRootLogger().info(msg, details, setStatus);
|
||||
};
|
||||
|
||||
var warn = function (msg, error, setStatus) {
|
||||
module.getRootLogger().warn(msg, error, setStatus);
|
||||
};
|
||||
|
||||
var error = function (msg, error, setStatus) {
|
||||
module.getRootLogger().error(msg, error, setStatus);
|
||||
};
|
||||
|
||||
var fatal = function (msg, error, setStatus) {
|
||||
module.getRootLogger().fatal(msg, error, setStatus);
|
||||
};
|
||||
|
||||
module.export({
|
||||
init: init,
|
||||
Logger: Logger,
|
||||
module: getModuleLogger,
|
||||
getRootLogger: getRootLogger,
|
||||
trace: trace,
|
||||
debug: debug,
|
||||
info: info,
|
||||
success: success,
|
||||
warn: warn,
|
||||
error: error,
|
||||
fata: fatal,
|
||||
TRACE_TRACE: TRACE_TRACE,
|
||||
TRACE_DEBUG: TRACE_DEBUG,
|
||||
TRACE_INFO: TRACE_INFO,
|
||||
TRACE_SUCCESS: TRACE_SUCCESS,
|
||||
TRACE_WARN: TRACE_WARN,
|
||||
TRACE_ERROR: TRACE_ERROR,
|
||||
TRACE_OFF: TRACE_OFF
|
||||
});
|
||||
});
|
@ -5,9 +5,12 @@
|
||||
* An addition can be registered for a specific selector e.g: <input data-addition-richtext ... />
|
||||
* It is possible to register multiple additions for the same selector.
|
||||
*/
|
||||
humhub.initModule('additions', function(module, require, $) {
|
||||
humhub.initModule('ui.additions', function (module, require, $) {
|
||||
|
||||
var event = require('event');
|
||||
|
||||
var _additions = {};
|
||||
|
||||
|
||||
/**
|
||||
* Registers an addition for a given jQuery selector. There can be registered
|
||||
* multiple additions for the same selector.
|
||||
@ -17,35 +20,47 @@ humhub.initModule('additions', function(module, require, $) {
|
||||
* @returns {undefined}
|
||||
*/
|
||||
module.registerAddition = function (selector, addition) {
|
||||
if(!_additions[selector]) {
|
||||
if (!_additions[selector]) {
|
||||
_additions[selector] = [];
|
||||
}
|
||||
|
||||
|
||||
_additions[selector].push(addition);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Applies all matched additions to the given element and its children
|
||||
* @param {type} element
|
||||
* @returns {undefined}
|
||||
*/
|
||||
module.applyTo = function(element) {
|
||||
module.applyTo = function (element) {
|
||||
var $element = $(element);
|
||||
$.each(_additions, function(selector, additions) {
|
||||
$.each(additions, function(i, addition) {
|
||||
$.each($element.find(selector).addBack(selector), function() {
|
||||
$.each(_additions, function (selector, additions) {
|
||||
$.each(additions, function (i, addition) {
|
||||
$.each($element.find(selector).addBack(selector), function () {
|
||||
try {
|
||||
var $match = $(this);
|
||||
addition.apply($match, [$match, $element]);
|
||||
} catch(e) {
|
||||
console.error('Error while applying addition '+addition+' on selector '+selector);
|
||||
} catch (e) {
|
||||
console.error('Error while applying addition on selector ' + selector, e);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.init = function() {
|
||||
|
||||
module.init = function () {
|
||||
event.on('humhub:modules:client:pjax:afterPageLoad', function (evt, cfg) {
|
||||
module.applyTo(cfg.options.container);
|
||||
});
|
||||
|
||||
event.on('humhub:afterInit', function (evt) {
|
||||
module.applyTo($('html'));
|
||||
});
|
||||
|
||||
this.registerAddition('.autosize', function ($match) {
|
||||
$match.autosize();
|
||||
});
|
||||
|
||||
//TODO: apply to html on startup, the problem is this could crash legacy code.
|
||||
};
|
||||
});
|
@ -1,8 +0,0 @@
|
||||
humhub.initModule('ui', function(module, require, $) {
|
||||
var additions = require('additions');
|
||||
module.init = function() {
|
||||
additions.registerAddition('.autosize', function($match) {
|
||||
$match.autosize();
|
||||
});
|
||||
};
|
||||
});
|
166
js/humhub/humhub.ui.loader.js
Normal file
166
js/humhub/humhub.ui.loader.js
Normal file
@ -0,0 +1,166 @@
|
||||
/**
|
||||
* Module for adding loader animations to dom nodes.
|
||||
*
|
||||
* The default loader animation can be added or appended/prepended as follows
|
||||
*
|
||||
* var loader = require('ui.loader');
|
||||
*
|
||||
* // Overwrite current html content with loader animation
|
||||
* loader.set(myNode);
|
||||
*
|
||||
* // Remove loader animation
|
||||
* loader.reset(myNode);
|
||||
*
|
||||
* The loader module also adds an click handler to all buttons and links with a
|
||||
* data-ui-loader attribute set.
|
||||
*
|
||||
* If a data-ui-loader button is used within a yii ActiveForm we automaticly reset all loader buttons
|
||||
* in case of form validation errors.
|
||||
*
|
||||
*
|
||||
* @param {type} param1
|
||||
* @param {type} param2
|
||||
*/
|
||||
humhub.initModule('ui.loader', function (module, require, $) {
|
||||
|
||||
var DEFAULT_LOADER_SELECTOR = '#humhub-ui-loader-default';
|
||||
|
||||
module.initOnPjaxLoad = false;
|
||||
|
||||
var set = function (node, cfg) {
|
||||
var $node = $(node);
|
||||
if ($node.length) {
|
||||
$node.each(function () {
|
||||
var $this = $(this);
|
||||
$this.data('htmlOld', $node.html());
|
||||
$this.html(getInstance(cfg));
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
var append = function (node, cfg) {
|
||||
var $node = $(node);
|
||||
if ($node.length) {
|
||||
$node.append(getInstance(cfg));
|
||||
}
|
||||
};
|
||||
|
||||
var prepend = function (node, cfg) {
|
||||
var $node = $(node);
|
||||
if ($node.length) {
|
||||
$node.prepend(getInstance(cfg));
|
||||
}
|
||||
};
|
||||
|
||||
var reset = function (node) {
|
||||
var $node = $(node);
|
||||
var $loader = $node.find('.loader').length;
|
||||
if (!$loader) {
|
||||
return;
|
||||
}
|
||||
|
||||
$node.removeClass('disabled');
|
||||
|
||||
if ($loader && $node.data('htmlOld')) {
|
||||
$node.html($node.data('htmlOld'));
|
||||
} else if ($loader) {
|
||||
$node.find('.loader').remove();
|
||||
}
|
||||
};
|
||||
|
||||
var getInstance = function (cfg) {
|
||||
cfg = cfg || {};
|
||||
|
||||
var $result = $(DEFAULT_LOADER_SELECTOR).clone().removeAttr('id').show();
|
||||
|
||||
if (cfg['cssClass']) {
|
||||
$result.addClass(cfg['cssClass']);
|
||||
}
|
||||
|
||||
if (cfg['id']) {
|
||||
$result.attr('id', cfg['id']);
|
||||
}
|
||||
|
||||
if (cfg['css']) {
|
||||
$result.css(cfg['css']);
|
||||
}
|
||||
|
||||
if (cfg['position']) {
|
||||
if (cfg['position'] === 'left') {
|
||||
$result.find('.sk-spinner').css('margin', '0');
|
||||
}
|
||||
$result.css(cfg['css']);
|
||||
}
|
||||
|
||||
if (cfg['size']) {
|
||||
var size = cfg['size'];
|
||||
$result.find('.sk-bounce1').css({'width': size, 'height': size});
|
||||
$result.find('.sk-bounce2').css({'width': size, 'height': size});
|
||||
$result.find('.sk-bounce3').css({'width': size, 'height': size});
|
||||
}
|
||||
|
||||
return $result;
|
||||
};
|
||||
|
||||
var init = function (cfg) {
|
||||
$(document).on('click.humhub:modules:ui:loader', 'a[data-ui-loader], button[data-ui-loader]', function (evt) {
|
||||
module.initLoaderButton(this, evt);
|
||||
});
|
||||
|
||||
$(document).on('afterValidate.humhub:modules:ui:loader', function (evt, messages, errors) {
|
||||
if (errors.length) {
|
||||
$(evt.target).find('[data-ui-loader]').each(function () {
|
||||
reset(this);
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var initLoaderButton = function (node, evt) {
|
||||
var $node = $(node);
|
||||
var loader = $node.find('.loader').length > 0;
|
||||
|
||||
/**
|
||||
* Prevent multiple mouse clicks, if originalEvent is present its a real mouse event otherwise its script triggered
|
||||
* This is a workaround since yii version 2.0.10 changed the activeForm submission from $form.submit() to data.submitObject.trigger("click");
|
||||
* which triggers this handler twice. Here we get sure not to block the script triggered submission.
|
||||
*/
|
||||
if (loader && evt.originalEvent) {
|
||||
return false;
|
||||
} else if (loader) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Adopt current color for the loader animation
|
||||
var color = $node.css('color') || '#ffffff';
|
||||
var $loader = $(module.template);
|
||||
|
||||
// Align bouncer animation color and size
|
||||
$loader.find('.sk-bounce1, .sk-bounce2, .sk-bounce3')
|
||||
.addClass('disabled')
|
||||
.css({'background-color': color, 'width': '10px', 'height': '10px'});
|
||||
|
||||
// The loader does have some margin we have to hide
|
||||
$node.css('overflow', 'hidden');
|
||||
$node.addClass('disabled');
|
||||
|
||||
// Prevent the container from resizing
|
||||
$node.css('min-width', node.getBoundingClientRect().width);
|
||||
$node.data('htmlOld', $node.html());
|
||||
$node.html($loader);
|
||||
};
|
||||
|
||||
var template = '<span class="loader"><span class="sk-spinner sk-spinner-three-bounce"><span class="sk-bounce1"></span><span class="sk-bounce2"></span><span class="sk-bounce3"></span></span></span>';
|
||||
|
||||
module.export({
|
||||
set: set,
|
||||
append: append,
|
||||
prepend: prepend,
|
||||
reset: reset,
|
||||
getInstance: getInstance,
|
||||
template: template,
|
||||
initLoaderButton: initLoaderButton,
|
||||
init: init
|
||||
});
|
||||
});
|
@ -17,14 +17,26 @@
|
||||
*/
|
||||
humhub.initModule('ui.modal', function (module, require, $) {
|
||||
var object = require('util').object;
|
||||
var additions = require('additions');
|
||||
var config = humhub.config.getModuleConfig('ui.modal');
|
||||
var additions = require('ui.additions');
|
||||
var config = require('config').module(module);
|
||||
|
||||
var loader = require('ui.loader');
|
||||
|
||||
module.initOnPjaxLoad = false;
|
||||
|
||||
//Keeps track of all initialized modals
|
||||
var modals = [];
|
||||
|
||||
var TMPL_MODAL_CONTAINER = '<div class="modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="display: none; background:rgba(0,0,0,0.1)"><div class="modal-dialog"><div class="modal-content"></div></div></div>';
|
||||
var TMPL_MODAL_HEADER = '<div class="modal-header"><button type="button" class="close" data-modal-close="true" aria-hidden="true">×</button><h4 class="modal-title"></h4></div>';
|
||||
var TMPL_MODAL_BODY = '<div class="modal-body"></div>';
|
||||
|
||||
/**
|
||||
* Template for the modal splitted into different parts. Those can be overwritten my changing or overwriting module.template.
|
||||
*/
|
||||
var template = {
|
||||
container : '<div class="modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true" style="display: none; background:rgba(0,0,0,0.1)"><div class="modal-dialog"><div class="modal-content"></div></div></div>',
|
||||
header : '<div class="modal-header"><button type="button" class="close" data-modal-close="true" aria-hidden="true">×</button><h4 class="modal-title"></h4></div>',
|
||||
body: '<div class="modal-body"></div>',
|
||||
}
|
||||
|
||||
var ERROR_DEFAULT_TITLE = 'Error';
|
||||
var ERROR_DEFAULT_MESSAGE = 'An unknown error occured!';
|
||||
|
||||
@ -50,7 +62,7 @@ humhub.initModule('ui.modal', function (module, require, $) {
|
||||
* @returns {undefined}
|
||||
*/
|
||||
Modal.prototype.createModal = function (id) {
|
||||
this.$modal = $(TMPL_MODAL_CONTAINER).attr('id', id);
|
||||
this.$modal = $(module.template.container).attr('id', id);
|
||||
$('body').append(this.$modal);
|
||||
};
|
||||
|
||||
@ -97,7 +109,7 @@ humhub.initModule('ui.modal', function (module, require, $) {
|
||||
* @returns {undefined}
|
||||
*/
|
||||
Modal.prototype.reset = function () {
|
||||
this.setBody('<div class="loader"><div class="sk-spinner sk-spinner-three-bounce"><div class="sk-bounce1"></div><div class="sk-bounce2"></div><div class="sk-bounce3"></div></div></div>');
|
||||
loader.set(this.$body);
|
||||
this.isFilled = false;
|
||||
};
|
||||
|
||||
@ -241,7 +253,7 @@ humhub.initModule('ui.modal', function (module, require, $) {
|
||||
Modal.prototype.setTitle = function (title) {
|
||||
var $header = this.getHeader();
|
||||
if (!$header.length) {
|
||||
this.getContent().prepend($(TMPL_MODAL_HEADER));
|
||||
this.getContent().prepend($(module.template.header));
|
||||
$header = this.getHeader();
|
||||
}
|
||||
$header.find('.modal-title').html(title);
|
||||
@ -255,7 +267,7 @@ humhub.initModule('ui.modal', function (module, require, $) {
|
||||
Modal.prototype.setBody = function (content) {
|
||||
var $body = this.getBody();
|
||||
if (!$body.length) {
|
||||
this.getContent().append($(TMPL_MODAL_BODY));
|
||||
this.getContent().append($(module.template.body));
|
||||
$body = this.getBody();
|
||||
}
|
||||
$body.html(content);
|
||||
@ -277,13 +289,14 @@ humhub.initModule('ui.modal', function (module, require, $) {
|
||||
return this.$modal.find('.modal-body');
|
||||
};
|
||||
|
||||
var ConfirmModal = function(id, cfg) {
|
||||
var ConfirmModal = function(id) {
|
||||
Modal.call(this, id);
|
||||
};
|
||||
|
||||
object.inherits(ConfirmModal, Modal);
|
||||
|
||||
ConfirmModal.prototype.open = function(cfg) {
|
||||
cfg = cfg || {};
|
||||
this.clear();
|
||||
cfg['header'] = cfg['header'] || config['defaultConfirmHeader'];
|
||||
cfg['body'] = cfg['body'] || config['defaultConfirmBody'];
|
||||
@ -323,8 +336,6 @@ humhub.initModule('ui.modal', function (module, require, $) {
|
||||
cfg['cancel'](evt);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
module.export({
|
||||
@ -335,6 +346,7 @@ humhub.initModule('ui.modal', function (module, require, $) {
|
||||
module.globalConfirm.open(cfg);
|
||||
};
|
||||
},
|
||||
Modal: Modal
|
||||
Modal: Modal,
|
||||
template: template
|
||||
});
|
||||
});
|
189
js/humhub/humhub.ui.status.js
Normal file
189
js/humhub/humhub.ui.status.js
Normal file
@ -0,0 +1,189 @@
|
||||
/**
|
||||
*
|
||||
* @param {type} param1
|
||||
* @param {type} param2
|
||||
*/
|
||||
humhub.initModule('ui.status', function (module, require, $) {
|
||||
|
||||
var event = require('event');
|
||||
var log = require('log');
|
||||
var object = require('util').object;
|
||||
|
||||
var SELECTOR_ROOT = '#status-bar';
|
||||
var SELECTOR_BODY = '.status-bar-body';
|
||||
var SELECTOR_CONTENT = '.status-bar-content';
|
||||
|
||||
var AUTOCLOSE_DELAY = 6000;
|
||||
|
||||
var StatusBar = function () {
|
||||
this.$ = $(SELECTOR_ROOT);
|
||||
};
|
||||
|
||||
StatusBar.prototype.info = function (msg, closeAfter) {
|
||||
closeAfter = closeAfter || AUTOCLOSE_DELAY;
|
||||
this._trigger('<i class="fa fa-info-circle info"></i><span>' + msg + '</span>', undefined, closeAfter);
|
||||
};
|
||||
|
||||
StatusBar.prototype.success = function (msg, closeAfter) {
|
||||
closeAfter = closeAfter || AUTOCLOSE_DELAY;
|
||||
this._trigger('<i class="fa fa-check-circle success"></i><span>' + msg + '</span>', undefined, closeAfter);
|
||||
};
|
||||
|
||||
StatusBar.prototype.warning = function (msg, error, closeAfter) {
|
||||
this._trigger('<i class="fa fa-exclamation-triangle warning"></i><span>' + msg + '</span>', error, closeAfter);
|
||||
};
|
||||
|
||||
StatusBar.prototype.error = function (msg, error, closeAfter) {
|
||||
this._trigger('<i class="fa fa-exclamation-circle error"></i><span>' + msg + '</span>', error, closeAfter);
|
||||
};
|
||||
|
||||
StatusBar.prototype._trigger = function (content, error, closeAfter) {
|
||||
if (this.closeTimer) {
|
||||
clearTimeout(this.closeTimer);
|
||||
}
|
||||
|
||||
var that = this;
|
||||
this.hide(function () {
|
||||
that.setContent(content, error).show(function () {
|
||||
if (closeAfter > 0) {
|
||||
that.closeTimer = setTimeout(function () {
|
||||
that.hide();
|
||||
}, closeAfter);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
StatusBar.prototype.setContent = function (content, error) {
|
||||
var that = this;
|
||||
var $content = this.$.find(SELECTOR_CONTENT).html(content);
|
||||
var $closeButton = $('<a class="status-bar-close pull-right" style="">×</a>');
|
||||
|
||||
if (error && module.config['showMore']) {
|
||||
this._addShowMoreButton($content, error);
|
||||
}
|
||||
|
||||
$closeButton.on('click', function () {
|
||||
that.hide();
|
||||
});
|
||||
|
||||
$content.prepend($closeButton);
|
||||
return this;
|
||||
};
|
||||
|
||||
StatusBar.prototype._addShowMoreButton = function ($content, error) {
|
||||
var $showMore = $('<a class="showMore"><i class="fa fa-angle-up"></i></a>');
|
||||
$showMore.on('click', function () {
|
||||
var $details = $content.find('.status-bar-details');
|
||||
if($details.length) {
|
||||
$details.stop().slideToggle('fast', function() {
|
||||
$details.remove();
|
||||
});
|
||||
|
||||
$showMore.find('i').attr('class', 'fa fa-angle-up');
|
||||
} else {
|
||||
$details = $('<div class="status-bar-details" style="display:none;"><pre>' + getErrorMessage(error) + '</pre><div>');
|
||||
$content.append($details);
|
||||
$details.slideToggle('fast');
|
||||
$showMore.find('i').attr('class', 'fa fa-angle-down');
|
||||
}
|
||||
});
|
||||
$content.append($showMore);
|
||||
};
|
||||
|
||||
var getErrorMessage = function (error) {
|
||||
try {
|
||||
if (!error) {
|
||||
return;
|
||||
} else if (object.isString(error)) {
|
||||
return error;
|
||||
} else if (error instanceof Error) {
|
||||
var result = error.toString();
|
||||
if(error.stack) {
|
||||
result += error.stack;
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return JSON.stringify(error, null, 4);
|
||||
}
|
||||
} catch (e) {
|
||||
log.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
StatusBar.prototype.show = function (callback) {
|
||||
// Make the container transparent for beeing able to measure the body height
|
||||
this.$.css('opacity', 0);
|
||||
this.$.show();
|
||||
|
||||
// Prepare the body node for animation, we set auto height to get the real node height
|
||||
var $body = this.$.find(SELECTOR_BODY).stop().css('height', 'auto');
|
||||
var height = $body.innerHeight();
|
||||
|
||||
// Hide element before animation
|
||||
$body.css({'opacity': '0', 'bottom': -height});
|
||||
|
||||
// Show root container
|
||||
this.$.css('opacity', 1);
|
||||
|
||||
$body.animate({bottom: '0', opacity: 1.0}, 500, function () {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
StatusBar.prototype.hide = function (callback) {
|
||||
var that = this;
|
||||
var $body = this.$.find(SELECTOR_BODY);
|
||||
var height = $body.innerHeight();
|
||||
|
||||
$body.stop().animate({bottom: -height, opacity:0}, 500, function () {
|
||||
that.$.hide();
|
||||
$body.css('bottom', '0');
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
var init = function () {
|
||||
module.statusBar = new StatusBar();
|
||||
event.on('humhub:modules:log:setStatus', function (evt, msg, details, level) {
|
||||
switch (level) {
|
||||
case log.TRACE_ERROR:
|
||||
case log.TRACE_FATAL:
|
||||
module.statusBar.error(msg, details);
|
||||
break;
|
||||
case log.TRACE_WARN:
|
||||
module.statusBar.warning(msg, details);
|
||||
break;
|
||||
case log.TRACE_SUCCESS:
|
||||
module.statusBar.success(msg);
|
||||
break;
|
||||
default:
|
||||
module.statusBar.info(msg);
|
||||
break;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.export({
|
||||
init: init,
|
||||
StatusBar: StatusBar,
|
||||
success: function (msg, closeAfter) {
|
||||
module.statusBar.success(msg, closeAfter);
|
||||
},
|
||||
info: function (msg, closeAfter) {
|
||||
module.statusBar.info(msg, closeAfter);
|
||||
},
|
||||
warn: function (msg, error, closeAfter) {
|
||||
module.statusBar.warn(msg, error, closeAfter);
|
||||
},
|
||||
error: function (msg, error, closeAfter) {
|
||||
module.statusBar.error(msg, error, closeAfter);
|
||||
}
|
||||
|
||||
});
|
||||
});
|
135
js/humhub/humhub.ui.tabbedForm.js
Normal file
135
js/humhub/humhub.ui.tabbedForm.js
Normal file
@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Module for creating an manipulating modal dialoges.
|
||||
* Normal layout of a dialog:
|
||||
*
|
||||
* <div class="modal">
|
||||
* <div class="modal-dialog">
|
||||
* <div class="modal-content">
|
||||
* <div class="modal-header"></div>
|
||||
* <div class="modal-body"></div>
|
||||
* <div class="modal-footer"></div>
|
||||
* </div>
|
||||
* </div>
|
||||
* </div>
|
||||
*
|
||||
* @param {type} param1
|
||||
* @param {type} param2
|
||||
*/
|
||||
humhub.initModule('ui.tabbedForm', function (module, require, $) {
|
||||
|
||||
|
||||
var additions = require('ui.additions');
|
||||
|
||||
/**
|
||||
* Prepares all included fieldsets for $form indexed
|
||||
* by its label (legend).
|
||||
*
|
||||
* @param {type} $form
|
||||
* @returns {$lastFieldSet$fieldSet} Array of fieldsets indexed by its label
|
||||
*/
|
||||
var getPreparedFieldSets = function ($form) {
|
||||
var result = {};
|
||||
var $lastFieldSet;
|
||||
|
||||
// Assamble all fieldsets with label
|
||||
$form.find('fieldset').each(function () {
|
||||
var $fieldSet = $(this).hide();
|
||||
|
||||
var legend = $fieldSet.children('legend').text();
|
||||
|
||||
// If we have a label we add the fieldset as is else we append its inputs to the previous fieldset
|
||||
if (legend && legend.length) {
|
||||
result[legend] = $lastFieldSet = $fieldSet;
|
||||
} else if($lastFieldSet) {
|
||||
$lastFieldSet.append($fieldSet.children(".form-group"));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check for errors in a specific category.
|
||||
* @param _object
|
||||
* @returns {boolean}
|
||||
*/
|
||||
var hasErrors = function($fieldSet) {
|
||||
return $fieldSet.find('.error, .has-error').length > 0;
|
||||
};
|
||||
|
||||
|
||||
var init = function () {
|
||||
additions.registerAddition('[data-ui-tabbed-form]', function ($form) {
|
||||
var activeTab = 0;
|
||||
|
||||
var $tabContent = $('<div class="tab-content"></div>');
|
||||
var $tabs = $('<ul id="profile-tabs" class="nav nav-tabs" data-tabs="tabs"></ul>');
|
||||
$form.prepend($tabContent);
|
||||
$form.prepend($tabs);
|
||||
|
||||
var index = 0;
|
||||
$.each(getPreparedFieldSets($form), function (label, $fieldSet) {
|
||||
|
||||
// activate this tab if there are any errors
|
||||
if (hasErrors($fieldSet)) {
|
||||
activeTab = index;
|
||||
}
|
||||
|
||||
// init tab structure
|
||||
$tabs.append('<li><a href="#tab-' + index + '" data-toggle="tab">' + label + '</a></li>');
|
||||
$tabContent.append('<div class="tab-pane" data-tab-index="' + index + '" id="tab-' + index + '"></div>');
|
||||
|
||||
// clone inputs from fieldSet into our tab structure
|
||||
var $inputs = $fieldSet.children(".form-group");
|
||||
$('#tab-' + index).html($inputs.clone());
|
||||
|
||||
// remove old fieldset from dom
|
||||
$fieldSet.remove();
|
||||
|
||||
// change tab on tab key for the last input of each tab
|
||||
var tabIndex = index;
|
||||
$tabContent.find('.form-control').last().on('keydown', function (e) {
|
||||
var keyCode = e.keyCode || e.which;
|
||||
|
||||
if (keyCode === 9) { //Tab
|
||||
var $nextTabLink = $tabs.find('a[href="#tab-' + (tabIndex + 1) + '"]');
|
||||
if ($nextTabLink.length) {
|
||||
e.preventDefault();
|
||||
$nextTabLink.tab('show');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
index++;
|
||||
});
|
||||
|
||||
// prepend error summary to form if exists
|
||||
var $errorSummary = $('.errorSummary');
|
||||
if ($errorSummary.length) {
|
||||
$form.prepend($errorSummary.clone());
|
||||
$errorSummary.remove();
|
||||
}
|
||||
|
||||
// focus first input on tab change
|
||||
$form.find('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
var tabId = $(e.target).attr('href'); // newly activated tab
|
||||
$(tabId).find('.form-control').first().focus();
|
||||
});
|
||||
|
||||
|
||||
// activate the first tab or the tab with errors
|
||||
$tabs.find('a[href="#tab-' + activeTab + '"]').tab('show');
|
||||
});
|
||||
|
||||
// Make sure frontend validation also activates the tab with errors.
|
||||
$(document).on('afterValidate.humhub:ui:tabbedForm', function (evt, messages, errors) {
|
||||
if (errors.length) {
|
||||
var index = $(errors[0].container).closest('.tab-pane').data('tab-index');
|
||||
$('a[href="#tab-' + index + '"]').tab('show');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.export({
|
||||
init: init
|
||||
});
|
||||
});
|
@ -166,23 +166,6 @@ $(document).ready(function () {
|
||||
setModalHandler();
|
||||
|
||||
initPlugins();
|
||||
|
||||
$(document).on('click', 'a[data-ui-loader], button[data-ui-loader]', function () {
|
||||
|
||||
});
|
||||
|
||||
$(document).on('afterValidate', function(evt, messages, errors) {
|
||||
if(errors.length) {
|
||||
$('[data-ui-loader]').each(function() {
|
||||
var $this = $(this);
|
||||
if($this.find('.loader').length) {
|
||||
$this.html($this.data('text'));
|
||||
$this.removeClass('disabled');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function setModalHandler() {
|
||||
|
112
js/tabbedForm.js
112
js/tabbedForm.js
@ -1,112 +0,0 @@
|
||||
$(document).ready(function () {
|
||||
/**
|
||||
* Prepares all included fieldsets for $form indexed
|
||||
* by its label (legend).
|
||||
*
|
||||
* @param {type} $form
|
||||
* @returns {$lastFieldSet$fieldSet} Array of fieldsets indexed by its label
|
||||
*/
|
||||
var getPreparedFieldSets = function ($form) {
|
||||
var result = {};
|
||||
var $lastFieldSet;
|
||||
|
||||
// Assamble all fieldsets with label
|
||||
$form.find('fieldset').each(function () {
|
||||
var $fieldSet = $(this).hide();
|
||||
|
||||
var legend = $fieldSet.children('legend').text();
|
||||
|
||||
// If we have a label we add the fieldset as is else we append its inputs to the previous fieldset
|
||||
if (legend && legend.length) {
|
||||
result[legend] = $lastFieldSet = $fieldSet;
|
||||
} else if($lastFieldSet) {
|
||||
$lastFieldSet.append($fieldSet.children(".form-group"));
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Check for errors in a specific category.
|
||||
* @param _object
|
||||
* @returns {boolean}
|
||||
*/
|
||||
var hasErrors = function($fieldSet) {
|
||||
return $fieldSet.find('.error, .has-error').length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize tabbed forms.
|
||||
* Note: this currently does only work with on form per page because of the tab id's
|
||||
*/
|
||||
$('[data-ui-tabbed-form]').each(function () {
|
||||
var activeTab = 0;
|
||||
|
||||
var $form = $(this);
|
||||
var $tabContent = $('<div class="tab-content"></div>');
|
||||
var $tabs = $('<ul id="profile-tabs" class="nav nav-tabs" data-tabs="tabs"></ul>');
|
||||
$form.prepend($tabContent);
|
||||
$form.prepend($tabs);
|
||||
|
||||
var index = 0;
|
||||
$.each(getPreparedFieldSets($form), function(label, $fieldSet) {
|
||||
|
||||
// activate this tab if there are any errors
|
||||
if (hasErrors($fieldSet)) {
|
||||
activeTab = index;
|
||||
}
|
||||
|
||||
// init tab structure
|
||||
$tabs.append('<li><a href="#tab-' + index + '" data-toggle="tab">' + label + '</a></li>');
|
||||
$tabContent.append('<div class="tab-pane" data-tab-index="'+index+'" id="tab-' + index + '"></div>');
|
||||
|
||||
// clone inputs from fieldSet into our tab structure
|
||||
var $inputs = $fieldSet.children(".form-group");
|
||||
$('#tab-' + index).html($inputs.clone());
|
||||
|
||||
// remove old fieldset from dom
|
||||
$fieldSet.remove();
|
||||
|
||||
// change tab on tab key for the last input of each tab
|
||||
var tabIndex = index;
|
||||
$tabContent.find('.form-control').last().on('keydown', function(e) {
|
||||
var keyCode = e.keyCode || e.which;
|
||||
|
||||
if(keyCode === 9) { //Tab
|
||||
var $nextTabLink = $tabs.find('a[href="#tab-' + (tabIndex+1) + '"]');
|
||||
if($nextTabLink.length) {
|
||||
e.preventDefault();
|
||||
$nextTabLink.tab('show');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
index++;
|
||||
});
|
||||
|
||||
// prepend error summary to form if exists
|
||||
var $errorSummary = $('.errorSummary');
|
||||
if ($errorSummary.length) {
|
||||
$form.prepend($errorSummary.clone());
|
||||
$errorSummary.remove();
|
||||
}
|
||||
|
||||
// focus first input on tab change
|
||||
$form.find('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
var tabId = $(e.target).attr('href'); // newly activated tab
|
||||
$(tabId).find('.form-control').first().focus();
|
||||
});
|
||||
|
||||
|
||||
// activate the first tab or the tab with errors
|
||||
$tabs.find('a[href="#tab-' + activeTab + '"]').tab('show');
|
||||
});
|
||||
|
||||
// Make sure frontend validation also activates the tab with errors.
|
||||
$(document).on('afterValidate', function(evt, messages, errors) {
|
||||
if(errors.length) {
|
||||
var index = $(errors[0].container).closest('.tab-pane').data('tab-index');
|
||||
$('a[href="#tab-' + index + '"]').tab('show');
|
||||
}
|
||||
});
|
||||
});
|
@ -45,13 +45,15 @@ class CoreApiAsset extends AssetBundle
|
||||
'js/humhub/legacy/app.js',
|
||||
'js/humhub/humhub.core.js',
|
||||
'js/humhub/humhub.util.js',
|
||||
'js/humhub/humhub.log.js',
|
||||
//'js/humhub/humhub.scripts.js',
|
||||
'js/humhub/humhub.additions.js',
|
||||
'js/humhub/humhub.ui.status.js',
|
||||
'js/humhub/humhub.ui.additions.js',
|
||||
'js/humhub/humhub.ui.loader.js',
|
||||
'js/humhub/humhub.ui.modal.js',
|
||||
'js/humhub/humhub.client.js',
|
||||
'js/humhub/humhub.client.pjax.js',
|
||||
'js/humhub/humhub.ui.js',
|
||||
'js/humhub/humhub.ui.modal.js',
|
||||
'js/humhub/humhub.actions.js'
|
||||
'js/humhub/humhub.action.js'
|
||||
];
|
||||
|
||||
/**
|
||||
|
91
protected/humhub/assets/HumHub.php
Executable file
91
protected/humhub/assets/HumHub.php
Executable file
@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\assets;
|
||||
|
||||
use yii\web\AssetBundle;
|
||||
|
||||
/**
|
||||
* The AppAsset assets are included in the core layout.
|
||||
* This Assetbundle includes some core dependencies and the humhub core api.
|
||||
*/
|
||||
class AppAsset extends AssetBundle
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $basePath = '@webroot';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $baseUrl = '@web';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $css = [
|
||||
'css/temp.css',
|
||||
'css/bootstrap-wysihtml5.css',
|
||||
'css/flatelements.css',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $jsOptions = ['position' => \yii\web\View::POS_BEGIN];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $js = [
|
||||
'js/ekko-lightbox-modified.js',
|
||||
//'js/modernizr.js', // In use???
|
||||
'js/jquery.highlight.min.js',
|
||||
//'js/wysihtml5-0.3.0.js',
|
||||
//'js/bootstrap3-wysihtml5.js',
|
||||
'js/desktop-notify-min.js',
|
||||
'js/desktop-notify-config.js',
|
||||
'js/jquery.nicescroll.min.js',
|
||||
'resources/file/fileuploader.js',
|
||||
'resources/user/userpicker.js',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $depends = [
|
||||
'yii\web\YiiAsset',
|
||||
'yii\bootstrap\BootstrapAsset',
|
||||
'yii\bootstrap\BootstrapPluginAsset',
|
||||
/**
|
||||
* Temporary disabled
|
||||
* https://github.com/inuyaksa/jquery.nicescroll/issues/574
|
||||
*/
|
||||
//'humhub\assets\JqueryNiceScrollAsset',
|
||||
'humhub\assets\BluebirdAsset',
|
||||
'humhub\assets\JqueryTimeAgoAsset',
|
||||
'humhub\assets\JqueryWidgetAsset',
|
||||
'humhub\assets\JqueryColorAsset', //TODO: only required for post/comment/stream
|
||||
'humhub\assets\JqueryPlaceholderAsset',
|
||||
'humhub\assets\FontAwesomeAsset',
|
||||
'humhub\assets\BlueimpFileUploadAsset',
|
||||
'humhub\assets\JqueryHighlightAsset',
|
||||
'humhub\assets\JqueryCookieAsset',
|
||||
'humhub\assets\JqueryAutosizeAsset',
|
||||
'humhub\assets\AtJsAsset',
|
||||
'humhub\assets\AnimateCssAsset',
|
||||
'humhub\assets\CoreApiAsset',
|
||||
'humhub\modules\content\assets\ContentAsset',
|
||||
'humhub\assets\NProgressAsset',
|
||||
'humhub\assets\IE9FixesAsset',
|
||||
'humhub\assets\IEFixesAsset',
|
||||
];
|
||||
|
||||
}
|
@ -18,7 +18,7 @@ use yii\web\AssetBundle;
|
||||
class TabbedFormAsset extends AssetBundle
|
||||
{
|
||||
|
||||
public $jsOptions = ['position' => \yii\web\View::POS_BEGIN];
|
||||
public $jsOptions = ['position' => \yii\web\View::POS_END];
|
||||
|
||||
public $basePath = '@webroot';
|
||||
public $baseUrl = '@web';
|
||||
@ -26,10 +26,10 @@ class TabbedFormAsset extends AssetBundle
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $js = ['js/tabbedForm.js'];
|
||||
public $js = ['js/humhub/humhub.ui.tabbedForm.js'];
|
||||
|
||||
public $depends = [
|
||||
'humhub\assets\AppAsset'
|
||||
'humhub\assets\CoreApiAsset'
|
||||
];
|
||||
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ class View extends \yii\web\View
|
||||
{
|
||||
|
||||
private $_pageTitle;
|
||||
private $jsConfig = [];
|
||||
|
||||
/**
|
||||
* Sets current page title
|
||||
@ -50,6 +51,21 @@ class View extends \yii\web\View
|
||||
$jsCode = "var " . $name . " = '" . addslashes($value) . "';\n";
|
||||
$this->registerJs($jsCode, View::POS_HEAD, $name);
|
||||
}
|
||||
|
||||
public function registerJsConfig($module, $params = null) {
|
||||
if(is_array($module)) {
|
||||
foreach($module as $moduleId => $value) {
|
||||
$this->registerJsConfig($moduleId, $value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if(isset($this->jsConfig[$module])) {
|
||||
$this->jsConfig[$module] = yii\helpers\ArrayHelper::merge($this->jsConfig[$module], $params);
|
||||
} else {
|
||||
$this->jsConfig[$module] = $params;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a string as Ajax including assets.
|
||||
@ -124,12 +140,16 @@ class View extends \yii\web\View
|
||||
*/
|
||||
public function endBody()
|
||||
{
|
||||
$this->registerJs("humhub.config.set(".json_encode($this->jsConfig).");", View::POS_BEGIN, 'jsConfig');
|
||||
|
||||
if (Yii::$app->request->isAjax) {
|
||||
return parent::endBody();
|
||||
}
|
||||
|
||||
echo \humhub\widgets\LayoutAddons::widget();
|
||||
|
||||
// Add Layout Addons
|
||||
return \humhub\widgets\LayoutAddons::widget() . parent::endBody();
|
||||
return parent::endBody();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
/**
|
||||
* This file is generated by the "yii asset" command.
|
||||
* DO NOT MODIFY THIS FILE DIRECTLY.
|
||||
* @version 2016-09-12 17:54:43
|
||||
* @version 2016-10-21 15:35:07
|
||||
*/
|
||||
return [
|
||||
'all' => [
|
||||
@ -10,11 +10,13 @@ return [
|
||||
'basePath' => '@webroot',
|
||||
'baseUrl' => '@web',
|
||||
'js' => [
|
||||
'js/all-cbb2ffbc142aa643edde05905376dd29.js',
|
||||
'js/all-a366b3723e2189716ce68fbe333d59bd.js',
|
||||
],
|
||||
'css' => [
|
||||
'css/all-5f84fd9cb4f93bb90cc038bed1ec4f2d.css',
|
||||
'css/all-2d605362857c9db6fdb10a1df599e902.css',
|
||||
],
|
||||
'sourcePath' => null,
|
||||
'depends' => [],
|
||||
],
|
||||
'yii\\web\\JqueryAsset' => [
|
||||
'sourcePath' => null,
|
||||
|
@ -87,7 +87,6 @@ $config = [
|
||||
'class' => '\humhub\components\AssetManager',
|
||||
'appendTimestamp' => true,
|
||||
'bundles' => require(__DIR__ . '/' . (YII_ENV_PROD ? 'assets-prod.php' : 'assets-dev.php')),
|
||||
#'bundles' => require(__DIR__ . '/' . 'assets-prod.php'),
|
||||
],
|
||||
'view' => [
|
||||
'class' => '\humhub\components\View',
|
||||
|
@ -12,10 +12,24 @@ Build
|
||||
- npm update (in humhub root)
|
||||
- npm install grunt --save-dev
|
||||
|
||||
|
||||
## Assets
|
||||
- Yii asset management http://www.yiiframework.com/doc-2.0/guide-structure-assets.html#combining-compressing-assets
|
||||
- php yii asset humhub/config/assets.php humhub/config/assets-prod.php
|
||||
|
||||
HumHub uses the Yii's build in mechanism for compressing and combining assets as javascript or stylesheet files in combination with grunt.
|
||||
HumHub will only use the compressed assets if operated in [production mode](admin-installation.md#disable-errors-debugging), otherwise
|
||||
all assets are included seperatly.
|
||||
|
||||
The compressed production assets are build by calling:
|
||||
|
||||
```
|
||||
yii asset humhub/config/assets.php humhub/config/assets-prod.php
|
||||
```
|
||||
|
||||
This will create the following files:
|
||||
|
||||
- /humhub/js/all-*.js - compressed js file with all core libraries
|
||||
- /humhub/css/all-*.css - compressed css files with all core stylesheets
|
||||
|
||||
More information is available on http://www.yiiframework.com/doc-2.0/guide-structure-assets.html#combining-compressing-assets
|
||||
|
||||
### Grunt Tasks
|
||||
- watch
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
Here you will learn how you can adapt existing modules to working fine with actually versions.
|
||||
|
||||
## Migrate from 1.1 to 1.2
|
||||
|
||||
## Migrate from 1.0 to 1.1
|
||||
|
||||
- Dropped unused space attribute "website"
|
||||
|
@ -2,6 +2,14 @@
|
||||
|
||||
Here you will learn how you can adapt existing themes to working fine with actually versions.
|
||||
|
||||
## Migrate to 1.2
|
||||
|
||||
### Stream
|
||||
|
||||
Set data-stream attributes for stream
|
||||
|
||||
### Status Bar
|
||||
|
||||
## Migrate to 1.1
|
||||
|
||||
- Make sure to update your themed less file with the latest version.
|
||||
|
26
protected/humhub/modules/activity/assets/ActivityAsset.php
Executable file
26
protected/humhub/modules/activity/assets/ActivityAsset.php
Executable file
@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\activity\assets;
|
||||
|
||||
use yii\web\AssetBundle;
|
||||
|
||||
class ActivityAsset extends AssetBundle
|
||||
{
|
||||
|
||||
public $sourcePath = '@activity/assets';
|
||||
public $css = [];
|
||||
public $js = [
|
||||
'js/humhub.activity.js'
|
||||
];
|
||||
|
||||
public $depends = [
|
||||
'humhub\assets\CoreApiAsset'
|
||||
];
|
||||
|
||||
}
|
134
protected/humhub/modules/activity/assets/js/humhub.activity.js
Normal file
134
protected/humhub/modules/activity/assets/js/humhub.activity.js
Normal file
@ -0,0 +1,134 @@
|
||||
/**
|
||||
* Core module for managing Streams and StreamItems
|
||||
* @type Function
|
||||
*/
|
||||
humhub.initModule('activity', function (module, require, $) {
|
||||
|
||||
var util = require('util');
|
||||
var object = util.object;
|
||||
var string = util.string;
|
||||
var stream = require('stream');
|
||||
var loader = require('ui.loader');
|
||||
var event = require('event');
|
||||
|
||||
/**
|
||||
* Number of initial stream enteis loaded when stream is initialized.
|
||||
* @type Number
|
||||
*/
|
||||
var STREAM_INIT_COUNT = 10;
|
||||
|
||||
/**
|
||||
* Number of stream entries loaded with each request (except initial request)
|
||||
* @type Number
|
||||
*/
|
||||
var STREAM_LOAD_COUNT = 10;
|
||||
|
||||
/**
|
||||
* Number of stream entries loaded with each request (except initial request)
|
||||
* @type Number
|
||||
*/
|
||||
var ACTIVITY_STREAM_SELECTOR = '#activityStream';
|
||||
|
||||
/**
|
||||
* ActivityStream instance;
|
||||
* @type ActivityStream
|
||||
*/
|
||||
var instance;
|
||||
|
||||
|
||||
var ActivityStreamEntry = function (id) {
|
||||
stream.StreamEntry.call(this, id);
|
||||
};
|
||||
|
||||
object.inherits(ActivityStreamEntry, stream.StreamEntry);
|
||||
|
||||
|
||||
ActivityStreamEntry.prototype.actions = function () {
|
||||
return [];
|
||||
};
|
||||
|
||||
ActivityStreamEntry.prototype.delete = function () {/* Not implemented */}
|
||||
ActivityStreamEntry.prototype.edit = function () {/* Not implemented */}
|
||||
|
||||
/**
|
||||
* ActivityStream implementation.
|
||||
*
|
||||
* @param {type} container id or jQuery object of the stream container
|
||||
* @returns {undefined}
|
||||
*/
|
||||
var ActivityStream = function (container) {
|
||||
stream.Stream.call(this, container, {
|
||||
'loadInitialCount': STREAM_INIT_COUNT,
|
||||
'loadCount': STREAM_LOAD_COUNT,
|
||||
'streamEntryClass': ActivityStreamEntry
|
||||
});
|
||||
};
|
||||
|
||||
object.inherits(ActivityStream, stream.Stream);
|
||||
|
||||
ActivityStream.prototype.showLoader = function() {
|
||||
var $loaderListItem = $('<li id="activityLoader" class="streamLoader">');
|
||||
loader.append($loaderListItem);
|
||||
this.$content.append($loaderListItem);
|
||||
};
|
||||
|
||||
ActivityStream.prototype.hideLoader = function() {
|
||||
this.$content.find('#activityLoader').remove();
|
||||
};
|
||||
|
||||
var getStream = function () {
|
||||
instance = instance || new ActivityStream($(ACTIVITY_STREAM_SELECTOR));
|
||||
return instance;
|
||||
};
|
||||
|
||||
var init = function () {
|
||||
instance = undefined;
|
||||
|
||||
var stream = getStream();
|
||||
|
||||
if (!stream) {
|
||||
console.log('No activity stream found!');
|
||||
return;
|
||||
}
|
||||
|
||||
stream.init();
|
||||
|
||||
var activityLastEntryReached = false;
|
||||
|
||||
// listen for scrolling event yes or no
|
||||
var scrolling = true;
|
||||
|
||||
stream.$content.scroll(function () {
|
||||
|
||||
// save height of the overflow container
|
||||
var _containerHeight = $("#activityContents").height();
|
||||
|
||||
// save scroll height
|
||||
var _scrollHeight = $("#activityContents").prop("scrollHeight");
|
||||
|
||||
// save current scrollbar position
|
||||
var _currentScrollPosition = $('#activityContents').scrollTop();
|
||||
|
||||
// load more activites if current scroll position is near scroll height
|
||||
if (_currentScrollPosition >= (_scrollHeight - _containerHeight - 30)) {
|
||||
// checking if ajax loading is necessary or the last entries are already loaded
|
||||
if (activityLastEntryReached == false) {
|
||||
if (scrolling == true) {
|
||||
// stop listening for scrolling event to load the new activity range only one time
|
||||
scrolling = false;
|
||||
// load more activities
|
||||
stream.loadEntries().finally(function() {
|
||||
scrolling = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.export({
|
||||
ActivityStream: ActivityStream,
|
||||
getStream: getStream,
|
||||
init: init
|
||||
});
|
||||
});
|
@ -1,5 +1,5 @@
|
||||
<?php if ($clickable): ?><a href="#" onClick="activityShowItem(<?= $record->id; ?>); return false;"><?php endif; ?>
|
||||
<li class="activity-entry">
|
||||
<li class="activity-entry" data-stream-entry data-action-component="activity.ActivityStreamEntry" data-content-key="<?= $record->content->id ?>">
|
||||
<div class="media">
|
||||
<?php if ($originator !== null) : ?>
|
||||
<!-- Show user image -->
|
||||
|
@ -54,11 +54,9 @@ class Stream extends \yii\base\Widget
|
||||
|
||||
protected function getStreamUrl()
|
||||
{
|
||||
$params = array(
|
||||
'limit' => '10',
|
||||
'from' => '-from-',
|
||||
$params = [
|
||||
'mode' => \humhub\modules\stream\actions\Stream::MODE_ACTIVITY
|
||||
);
|
||||
];
|
||||
|
||||
if ($this->contentContainer) {
|
||||
return $this->contentContainer->createUrl($this->streamAction, $params);
|
||||
|
@ -1,9 +1,10 @@
|
||||
<?php
|
||||
/* @var $this humhub\components\View */
|
||||
|
||||
\humhub\modules\activity\assets\ActivityAsset::register($this);
|
||||
|
||||
$this->registerJsFile('@web/resources/activity/activies.js');
|
||||
$this->registerJsVar('activityStreamUrl', $streamUrl);
|
||||
//$this->registerJsFile('@web/resources/activity/activies.js');
|
||||
//$this->registerJsVar('activityStreamUrl', $streamUrl);
|
||||
$this->registerJsVar('activityInfoUrl', $infoUrl);
|
||||
?>
|
||||
|
||||
@ -11,13 +12,13 @@ $this->registerJsVar('activityInfoUrl', $infoUrl);
|
||||
|
||||
<div
|
||||
class="panel-heading"><?php echo Yii::t('ActivityModule.widgets_views_activityStream', '<strong>Latest</strong> activities'); ?></div>
|
||||
<div id="activityStream">
|
||||
<div id="activityStream" data-stream="<?= $streamUrl ?>">
|
||||
<div id="activityEmpty" style="display:none">
|
||||
<div
|
||||
class="placeholder"><?php echo Yii::t('ActivityModule.widgets_views_activityStream', 'There are no activities yet.'); ?></div>
|
||||
</div>
|
||||
<ul id="activityContents" class="media-list activities">
|
||||
<li id="activityLoader">
|
||||
<ul id="activityContents" class="media-list activities" data-stream-content>
|
||||
<li id="activityLoader" class="streamLoader">
|
||||
<?php echo \humhub\widgets\LoaderWidget::widget(); ?>
|
||||
</li>
|
||||
</ul>
|
||||
|
@ -20,7 +20,6 @@ use humhub\models\Setting;
|
||||
<div class="form-group">
|
||||
<?php echo $form->labelEx($model, 'expireTime'); ?>
|
||||
<?php echo $form->textField($model, 'expireTime', array('class' => 'form-control', 'readonly' => Setting::IsFixed('cache.expireTime'))); ?>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
|
28
protected/humhub/modules/content/assets/ContentFormAsset.php
Executable file
28
protected/humhub/modules/content/assets/ContentFormAsset.php
Executable file
@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2015 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\content\assets;
|
||||
|
||||
use yii\web\AssetBundle;
|
||||
|
||||
class ContentFormAsset extends AssetBundle
|
||||
{
|
||||
|
||||
public $jsOptions = ['position' => \yii\web\View::POS_END];
|
||||
|
||||
public $sourcePath = '@content/assets';
|
||||
public $css = [];
|
||||
public $js = [
|
||||
'js/humhub.content.form.js'
|
||||
];
|
||||
|
||||
public $depends = [
|
||||
'humhub\assets\CoreApiAsset'
|
||||
];
|
||||
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Core module for managing Streams and StreamItems
|
||||
* @type Function
|
||||
*/
|
||||
humhub.initModule('content.form', function (module, require, $) {
|
||||
|
||||
var CREATE_FORM_ROOT_SELECTOR = '#contentFormBody';
|
||||
|
||||
var util = require('util');
|
||||
var client = require('client');
|
||||
|
||||
var config = require('config').module(module);
|
||||
var event = require('event');
|
||||
|
||||
var instance;
|
||||
|
||||
var CreateForm = function () {
|
||||
this.$ = $(CREATE_FORM_ROOT_SELECTOR);
|
||||
};
|
||||
|
||||
CreateForm.prototype.init = function () {
|
||||
this.$.hide();
|
||||
|
||||
// Hide options by default
|
||||
$('.contentForm_options').hide();
|
||||
$('#contentFormError').hide();
|
||||
// Remove info text from the textinput
|
||||
$('#contentFormBody').click(function () {
|
||||
// Hide options by default
|
||||
$('.contentForm_options').fadeIn();
|
||||
});
|
||||
|
||||
this.setDefaultVisibility();
|
||||
|
||||
this.$.fadeIn('fast');
|
||||
}
|
||||
|
||||
CreateForm.prototype.actions = function () {
|
||||
return ['submit', 'notifyUser', 'changeVisibility'];
|
||||
};
|
||||
|
||||
CreateForm.prototype.submit = function (evt) {
|
||||
$("#contentFormError").hide();
|
||||
$("#contentFormError li").remove();
|
||||
$(".contentForm_options .btn").hide();
|
||||
$("#postform-loader").removeClass("hidden");
|
||||
|
||||
var that = this;
|
||||
client.submit(this.getForm(), {url: evt.url}).then(function (response) {
|
||||
if (!response.errors) {
|
||||
event.trigger('humhub:modules:content:newEntry', response.output);
|
||||
that.resetForm();
|
||||
} else {
|
||||
that.handleError(response);
|
||||
}
|
||||
$('.contentForm_options .btn').show();
|
||||
$('#postform-loader').addClass('hidden');
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Todo: this is post form only, this needs to be added to post module perhaps by calling $form.trigger('humhub:form:clear');
|
||||
* @returns {undefined}
|
||||
*/
|
||||
CreateForm.prototype.resetForm = function () {
|
||||
// Reset Form (Empty State)
|
||||
$('.contentForm_options').hide();
|
||||
$('.contentForm').filter(':text').val('');
|
||||
$('.contentForm').filter('textarea').val('').trigger('autosize.resize');
|
||||
$('.contentForm').attr('checked', false);
|
||||
$('.userInput').remove(); // used by UserPickerWidget
|
||||
$('#notifyUserContainer').addClass('hidden');
|
||||
$('#notifyUserInput').val('');
|
||||
|
||||
this.setDefaultVisibility();
|
||||
|
||||
$('#contentFrom_files').val('');
|
||||
$('#public').attr('checked', false);
|
||||
$('#contentForm_message_contenteditable').addClass('atwho-placeholder');
|
||||
|
||||
$('#contentFormBody').find('.atwho-input').trigger('clear');
|
||||
|
||||
// Notify FileUploadButtonWidget to clear (by providing uploaderId)
|
||||
// TODO: use api
|
||||
resetUploader('contentFormFiles');
|
||||
};
|
||||
|
||||
CreateForm.prototype.handleError = function (response) {
|
||||
$('#contentFormError').show();
|
||||
$.each(response.errors, function (fieldName, errorMessage) {
|
||||
// Mark Fields as Error
|
||||
var fieldId = 'contentForm_' + fieldName;
|
||||
$('#' + fieldId).addClass('error');
|
||||
$.each(errorMessage, function (key, msg) {
|
||||
$('#contentFormError').append('<li><i class=\"icon-warning-sign\"></i> ' + msg + '</li>');
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
CreateForm.prototype.getForm = function () {
|
||||
return this.$.find('form:visible');
|
||||
};
|
||||
|
||||
CreateForm.prototype.changeVisibility = function() {
|
||||
if (!$('#contentForm_visibility').prop('checked')) {
|
||||
this.setPublicVisibility();
|
||||
} else {
|
||||
this.setPrivateVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
CreateForm.prototype.setDefaultVisibility = function() {
|
||||
if (config['defaultVisibility']) {
|
||||
this.setPublicVisibility();
|
||||
} else {
|
||||
this.setPrivateVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
CreateForm.prototype.setPublicVisibility = function() {
|
||||
$('#contentForm_visibility').prop("checked", true);
|
||||
$('#contentForm_visibility_entry').html('<i class="fa fa-lock"></i>'+config['text']['makePrivate']);
|
||||
$('.label-public').removeClass('hidden');
|
||||
}
|
||||
|
||||
CreateForm.prototype.setPrivateVisibility = function() {
|
||||
$('#contentForm_visibility').prop("checked", false);
|
||||
$('#contentForm_visibility_entry').html('<i class="fa fa-unlock"></i>'+config['text']['makePublic']);
|
||||
$('.label-public').addClass('hidden');
|
||||
}
|
||||
|
||||
CreateForm.prototype.notifyUser = function() {
|
||||
$('#notifyUserContainer').removeClass('hidden');
|
||||
$('#notifyUserInput_tag_input_field').focus();
|
||||
}
|
||||
|
||||
var init = function () {
|
||||
instance = new CreateForm();
|
||||
instance.init();
|
||||
};
|
||||
|
||||
module.export({
|
||||
CreateForm: CreateForm,
|
||||
instance: instance,
|
||||
init: init
|
||||
});
|
||||
});
|
@ -7,8 +7,9 @@
|
||||
humhub.initModule('content', function(module, require, $) {
|
||||
var client = require('client');
|
||||
var object = require('util').object;
|
||||
var actions = require('actions');
|
||||
var actions = require('action');
|
||||
var Component = actions.Component;
|
||||
var event = require('event');
|
||||
|
||||
var DATA_CONTENT_KEY = "content-key";
|
||||
var DATA_CONTENT_EDIT_URL = "content-edit-url";
|
||||
@ -20,6 +21,10 @@ humhub.initModule('content', function(module, require, $) {
|
||||
Component.call(this, container);
|
||||
};
|
||||
|
||||
Content.getNodeByKey = function(key) {
|
||||
return $('[data-content-key="'+key+'"]');
|
||||
};
|
||||
|
||||
object.inherits(Content, Component);
|
||||
|
||||
Content.prototype.actions = function() {
|
||||
@ -30,6 +35,7 @@ humhub.initModule('content', function(module, require, $) {
|
||||
return this.$.data(DATA_CONTENT_KEY);
|
||||
};
|
||||
|
||||
//TODO: return promise
|
||||
Content.prototype.create = function (addContentHandler) {
|
||||
//Note that this Content won't have an id, so the backend will create an instance
|
||||
if(this.hasAction('create')) {
|
||||
@ -39,6 +45,7 @@ humhub.initModule('content', function(module, require, $) {
|
||||
this.edit(addContentHandler);
|
||||
};
|
||||
|
||||
//TODO: return promise
|
||||
Content.prototype.edit = function (successHandler) {
|
||||
if(!this.hasAction('edit')) {
|
||||
return;
|
||||
@ -91,12 +98,13 @@ humhub.initModule('content', function(module, require, $) {
|
||||
},
|
||||
error: function(errResponse) {
|
||||
modal.error(errResponse);
|
||||
console.log('Error occured while editing content: '+errResponse.getFirstError());
|
||||
console.error('Error occured while editing content: '+errResponse.getFirstError());
|
||||
//Todo: handle error
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
//TODO: return promise
|
||||
Content.prototype.delete = function () {
|
||||
if(!this.hasAction('delete')) {
|
||||
return;
|
||||
@ -127,10 +135,14 @@ humhub.initModule('content', function(module, require, $) {
|
||||
|
||||
Content.prototype.remove = function() {
|
||||
var that = this;
|
||||
this.$.animate({ height: 'toggle', opacity: 'toggle' }, 'fast', function() {
|
||||
that.$.remove();
|
||||
//TODO: fire global event
|
||||
return new Promise(function(resolve, reject) {
|
||||
that.$.animate({ height: 'toggle', opacity: 'toggle' }, 'fast', function() {
|
||||
that.$.remove();
|
||||
event.trigger('humhub:modules:content:afterRemove', that);
|
||||
resolve(that);
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
module.export({
|
||||
|
@ -97,7 +97,6 @@ class ContentController extends Controller
|
||||
$content->archive();
|
||||
|
||||
$json['success'] = true;
|
||||
$json['wallEntryIds'] = $content->getWallEntryIds();
|
||||
}
|
||||
|
||||
return $json;
|
||||
@ -123,7 +122,6 @@ class ContentController extends Controller
|
||||
$content->unarchive();
|
||||
|
||||
$json['success'] = true;
|
||||
$json['wallEntryIds'] = $content->getWallEntryIds();
|
||||
}
|
||||
|
||||
return $json;
|
||||
@ -149,7 +147,7 @@ class ContentController extends Controller
|
||||
$content->stick();
|
||||
|
||||
$json['success'] = true;
|
||||
$json['wallEntryIds'] = $content->getWallEntryIds();
|
||||
$json['contentId'] = $content->id;
|
||||
} else {
|
||||
$json['errorMessage'] = Yii::t('ContentModule.controllers_ContentController', "Maximum number of sticked items reached!\n\nYou can stick only two items at once.\nTo however stick this item, unstick another before!");
|
||||
}
|
||||
@ -178,7 +176,6 @@ class ContentController extends Controller
|
||||
if ($content !== null && $content->canStick()) {
|
||||
$content->unstick();
|
||||
$json['success'] = true;
|
||||
$json['wallEntryIds'] = $content->getWallEntryIds();
|
||||
}
|
||||
|
||||
return $json;
|
||||
|
@ -45,36 +45,13 @@ class PermaController extends Controller
|
||||
$id = (int) Yii::$app->request->get('id', "");
|
||||
|
||||
$content = Content::findOne(['id' => $id]);
|
||||
|
||||
if ($content !== null) {
|
||||
return $this->redirect($content->getUrl());
|
||||
return $this->redirect($content->container->createUrl(null, array('contentId' => $id)));
|
||||
}
|
||||
|
||||
throw new HttpException(404, Yii::t('ContentModule.controllers_PermaController', 'Could not find requested content!'));
|
||||
}
|
||||
|
||||
/**
|
||||
* On given WallEntryId redirect the user to the corresponding content object.
|
||||
*
|
||||
* This is mainly used by ActivityStream or Permalinks.
|
||||
*/
|
||||
public function actionWallEntry()
|
||||
{
|
||||
|
||||
// Id of wall entry
|
||||
$id = Yii::$app->request->get('id', "");
|
||||
|
||||
$wallEntry = WallEntry::find()->joinWith('content')->where(['wall_entry.id' => $id])->one();
|
||||
|
||||
if ($wallEntry != null) {
|
||||
$obj = $wallEntry->content; // Type of IContent
|
||||
if ($obj) {
|
||||
return $this->redirect($obj->container->createUrl(null, array('wallEntryId' => $id)));
|
||||
}
|
||||
}
|
||||
|
||||
throw new HttpException(404, Yii::t('ContentModule.controllers_PermaController', 'Could not find requested permalink!'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
@ -3,15 +3,18 @@
|
||||
|
||||
use yii\helpers\Url;
|
||||
|
||||
$this->registerJsVar('wallArchiveLinkUrl', Url::to(['/content/content/archive', 'id' => '-id-']));
|
||||
$this->registerJsVar('wallUnarchiveLinkUrl', Url::to(['/content/content/unarchive', 'id' => '-id-']));
|
||||
$archiveLink = Url::to(['/content/content/archive', 'id' => $id]);
|
||||
$unarchiveLink = Url::to(['/content/content/unarchive', 'id' => $id]);
|
||||
|
||||
?>
|
||||
<li>
|
||||
<?php if ($object->content->isArchived()): ?>
|
||||
<a href="#" onClick="wallUnarchive('<?php echo $id; ?>');
|
||||
return false;"><i class="fa fa-archive"></i> <?php echo Yii::t('ContentModule.widgets_views_archiveLink', 'Unarchive'); ?></a>
|
||||
<a href="#" data-action-click="unarchive" data-action-url="<?= $unarchiveLink ?>">
|
||||
<i class="fa fa-archive"></i> <?php echo Yii::t('ContentModule.widgets_views_archiveLink', 'Unarchive'); ?>
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<a href="#" onClick="wallArchive('<?php echo $id; ?>');
|
||||
return false;"><i class="fa fa-archive"></i> <?php echo Yii::t('ContentModule.widgets_views_archiveLink', 'Move to archive'); ?></a>
|
||||
<a href="#" data-action-click="archive" data-action-url="<?= $archiveLink ?>">
|
||||
<i class="fa fa-archive"></i> <?php echo Yii::t('ContentModule.widgets_views_archiveLink', 'Move to archive'); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
|
@ -9,17 +9,4 @@ use yii\helpers\Url;
|
||||
<a href="#" data-action-click="delete">
|
||||
<i class="fa fa-trash-o"></i> <?= Yii::t('ContentModule.widgets_views_deleteLink', 'Delete') ?>
|
||||
</a>
|
||||
<?php
|
||||
/*echo humhub\widgets\ModalConfirm::widget(array(
|
||||
'uniqueID' => 'modal_postdelete_' . $id,
|
||||
'linkOutput' => 'a',
|
||||
'title' => Yii::t('ContentModule.widgets_views_deleteLink', '<strong>Confirm</strong> post deleting'),
|
||||
'message' => Yii::t('ContentModule.widgets_views_deleteLink', 'Do you really want to delete this post? All likes and comments will be lost!'),
|
||||
'buttonTrue' => Yii::t('ContentModule.widgets_views_deleteLink', 'Delete'),
|
||||
'buttonFalse' => Yii::t('ContentModule.widgets_views_deleteLink', 'Cancel'),
|
||||
'linkContent' => '<i class="fa fa-trash-o"></i> ' . Yii::t('ContentModule.widgets_views_deleteLink', 'Delete'),
|
||||
'linkHref' => Url::to(['/content/content/delete', 'model' => $model, 'id' => $id]),
|
||||
'confirmJS' => 'function(json) { $(".wall_"+json.uniqueId).remove(); }'
|
||||
));*/
|
||||
?>
|
||||
</li>
|
@ -1,23 +1,9 @@
|
||||
<?php
|
||||
|
||||
|
||||
use yii\web\JsExpression;
|
||||
|
||||
/* @var $this humhub\components\View */
|
||||
?>
|
||||
<li>
|
||||
<?php
|
||||
echo \humhub\widgets\AjaxButton::widget([
|
||||
'label' => '<i class="fa fa-pencil"></i> ' . Yii::t('ContentModule.widgets_views_editLink', 'Edit'),
|
||||
'tag' => 'a',
|
||||
'ajaxOptions' => [
|
||||
'type' => 'POST',
|
||||
'success' => new JsExpression('function(html){ $(".preferences .dropdown").removeClass("open"); $("#wall_content_' . $content->getUniqueId() . '").replaceWith(html); }'),
|
||||
'url' => $editUrl,
|
||||
],
|
||||
'htmlOptions' => [
|
||||
'href' => '#'
|
||||
]
|
||||
]);
|
||||
?>
|
||||
<a href="#" data-action-click="edit"
|
||||
data-action-url="<?= $editUrl ?>"><i class="fa fa-pencil"></i> <?= Yii::t('ContentModule.widgets_views_editLink', 'Edit') ?></a>
|
||||
|
||||
</li>
|
||||
|
@ -1,9 +1,11 @@
|
||||
<li>
|
||||
<?php if ($isSticked): ?>
|
||||
<a href="#" onClick="wallUnstick('<?php echo $unstickUrl; ?>');
|
||||
return false;"><i class="fa fa-arrow-up"></i> <?php echo Yii::t('ContentModule.widgets_views_stickLink', 'Unstick'); ?></a>
|
||||
<a href="#" data-action-click="unstick" data-action-url="<?= $unstickUrl ?>">
|
||||
<i class="fa fa-arrow-up"></i> <?php echo Yii::t('ContentModule.widgets_views_stickLink', 'Unstick'); ?>
|
||||
</a>
|
||||
<?php else: ?>
|
||||
<a href="#" onClick="wallStick('<?php echo $stickUrl; ?>');
|
||||
return false;"><i class="fa fa-arrow-up"></i> <?php echo Yii::t('ContentModule.widgets_views_stickLink', 'Stick'); ?></a>
|
||||
<a href="#" data-action-click="stick" data-action-url="<?= $stickUrl ?>">
|
||||
<i class="fa fa-arrow-up"></i> <?php echo Yii::t('ContentModule.widgets_views_stickLink', 'Stick'); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
</li>
|
||||
|
@ -3,11 +3,22 @@
|
||||
use yii\helpers\Html;
|
||||
use yii\helpers\Url;
|
||||
use humhub\modules\space\models\Space;
|
||||
|
||||
\humhub\modules\content\assets\ContentFormAsset::register($this);
|
||||
|
||||
?>
|
||||
|
||||
<?php
|
||||
$this->registerJsConfig('content.form', [
|
||||
'defaultVisibility' => $defaultVisibility,
|
||||
'text' => [
|
||||
'makePrivate' => Yii::t('ContentModule.widgets_views_contentForm', 'Make private'),
|
||||
'makePublic' => Yii::t('ContentModule.widgets_views_contentForm', 'Make public')
|
||||
]]);
|
||||
?>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body" id="contentFormBody">
|
||||
|
||||
<div class="panel-body" id="contentFormBody" style="display:none;" data-action-component="content.form.CreateForm" data-action-param="{defaultVisibility: <?= $defaultVisibility ?>}">
|
||||
<?php echo Html::beginForm('', 'POST'); ?>
|
||||
|
||||
<ul id="contentFormError">
|
||||
@ -48,25 +59,11 @@ use humhub\modules\space\models\Space;
|
||||
<div class="btn_container">
|
||||
|
||||
<?php echo \humhub\widgets\LoaderWidget::widget(['id' => 'postform-loader', 'cssClass' => 'loader-postform hidden']); ?>
|
||||
|
||||
<?php
|
||||
echo \humhub\widgets\AjaxButton::widget([
|
||||
'label' => $submitButtonText,
|
||||
'ajaxOptions' => [
|
||||
'url' => $submitUrl,
|
||||
'type' => 'POST',
|
||||
'dataType' => 'json',
|
||||
'beforeSend' => "function() { $('.contentForm').removeClass('error'); $('#contentFormError').hide(); $('#contentFormError').empty(); }",
|
||||
'beforeSend' => 'function(){ $("#contentFormError").hide(); $("#contentFormError li").remove(); $(".contentForm_options .btn").hide(); $("#postform-loader").removeClass("hidden"); }',
|
||||
'success' => "function(response) { handleResponse(response);}"
|
||||
],
|
||||
'htmlOptions' => [
|
||||
'id' => "post_submit_button",
|
||||
'data-action' => 'post_create',
|
||||
'class' => 'btn btn-info',
|
||||
'type' => 'submit'
|
||||
]]);
|
||||
?>
|
||||
|
||||
<button id="post_submit_button" data-action-click="submit" data-action-url="<?= $submitUrl ?>" class="btn btn-info">
|
||||
<?= $submitButtonText ?>
|
||||
</button>
|
||||
|
||||
<?php
|
||||
// Creates Uploading Button
|
||||
echo humhub\modules\file\widgets\FileUploadButton::widget(array(
|
||||
@ -74,20 +71,6 @@ use humhub\modules\space\models\Space;
|
||||
'fileListFieldName' => 'fileList',
|
||||
));
|
||||
?>
|
||||
<script>
|
||||
$('#fileUploaderButton_contentFormFiles').bind('fileuploaddone', function (e, data) {
|
||||
$('.btn_container').show();
|
||||
});
|
||||
$('#fileUploaderButton_contentFormFiles').bind('fileuploadprogressall', function (e, data) {
|
||||
var progress = parseInt(data.loaded / data.total * 100, 10);
|
||||
if (progress != 100) {
|
||||
// Fix: remove focus from upload button to hide tooltip
|
||||
$('#post_submit_button').focus();
|
||||
// hide form buttons
|
||||
$('.btn_container').hide();
|
||||
}
|
||||
});</script>
|
||||
|
||||
|
||||
<!-- public checkbox -->
|
||||
<?php echo Html::checkbox("visibility", "", array('id' => 'contentForm_visibility', 'class' => 'contentForm hidden')); ?>
|
||||
@ -103,14 +86,14 @@ use humhub\modules\space\models\Space;
|
||||
class="fa fa-cogs"></i></a>
|
||||
<ul class="dropdown-menu pull-right">
|
||||
<li>
|
||||
<a href="javascript:notifyUser();"><i
|
||||
class="fa fa-bell"></i> <?php echo Yii::t('ContentModule.widgets_views_contentForm', 'Notify members'); ?>
|
||||
<a data-action-click="notifyUser">
|
||||
<i class="fa fa-bell"></i> <?php echo Yii::t('ContentModule.widgets_views_contentForm', 'Notify members'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php if ($canSwitchVisibility): ?>
|
||||
<li>
|
||||
<a id="contentForm_visibility_entry" href="javascript:changeVisibility();"><i
|
||||
class="fa fa-unlock"></i> <?php echo Yii::t('ContentModule.widgets_views_contentForm', 'Make public'); ?>
|
||||
<a id="contentForm_visibility_entry" data-action-click="changeVisibility">
|
||||
<i class="fa fa-unlock"></i> <?php echo Yii::t('ContentModule.widgets_views_contentForm', 'Make public'); ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
@ -129,102 +112,12 @@ use humhub\modules\space\models\Space;
|
||||
'uploaderId' => 'contentFormFiles'
|
||||
));
|
||||
?>
|
||||
|
||||
</div>
|
||||
<!-- /contentForm_Options -->
|
||||
<!-- /contentForm_Options -->
|
||||
<?php echo Html::endForm(); ?>
|
||||
|
||||
</div>
|
||||
<!-- /panel body -->
|
||||
</div> <!-- /panel -->
|
||||
|
||||
<div class="clearFloats"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
// Hide options by default
|
||||
jQuery('.contentForm_options').hide();
|
||||
$('#contentFormError').hide();
|
||||
// Remove info text from the textinput
|
||||
jQuery('#contentFormBody').click(function () {
|
||||
|
||||
// Hide options by default
|
||||
jQuery('.contentForm_options').fadeIn();
|
||||
});
|
||||
|
||||
setDefaultVisibility();
|
||||
|
||||
function setDefaultVisibility() {
|
||||
<?php if ($defaultVisibility == humhub\modules\content\models\Content::VISIBILITY_PRIVATE) : ?>
|
||||
setPrivateVisibility();
|
||||
<?php endif ;?>
|
||||
|
||||
<?php if ($defaultVisibility == humhub\modules\content\models\Content::VISIBILITY_PUBLIC) : ?>
|
||||
setPublicVisibility();
|
||||
<?php endif ;?>
|
||||
}
|
||||
|
||||
function setPublicVisibility() {
|
||||
$('#contentForm_visibility').prop( "checked", true );
|
||||
$('#contentForm_visibility_entry').html('<i class="fa fa-lock"></i> <?php echo Yii::t('ContentModule.widgets_views_contentForm', 'Make private'); ?>');
|
||||
$('.label-public').removeClass('hidden');
|
||||
}
|
||||
|
||||
function setPrivateVisibility() {
|
||||
$('#contentForm_visibility').prop( "checked", false );
|
||||
$('#contentForm_visibility_entry').html('<i class="fa fa-unlock"></i> <?php echo Yii::t('ContentModule.widgets_views_contentForm', 'Make public'); ?>');
|
||||
$('.label-public').addClass('hidden');
|
||||
}
|
||||
|
||||
function changeVisibility() {
|
||||
if (!$('#contentForm_visibility').prop('checked')) {
|
||||
setPublicVisibility();
|
||||
} else {
|
||||
setPrivateVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
function notifyUser() {
|
||||
$('#notifyUserContainer').removeClass('hidden');
|
||||
$('#notifyUserInput_tag_input_field').focus();
|
||||
}
|
||||
|
||||
function handleResponse(response) {
|
||||
if (!response.errors) {
|
||||
// application.modules_core.wall function
|
||||
humhub.modules.stream.getStream().appendEntry(response);
|
||||
|
||||
// Reset Form (Empty State)
|
||||
jQuery('.contentForm_options').hide();
|
||||
$('.contentForm').filter(':text').val('');
|
||||
$('.contentForm').filter('textarea').val('').trigger('autosize.resize');
|
||||
$('.contentForm').attr('checked', false);
|
||||
$('.userInput').remove(); // used by UserPickerWidget
|
||||
$('#notifyUserContainer').addClass('hidden');
|
||||
$('#notifyUserInput').val('');
|
||||
|
||||
setDefaultVisibility();
|
||||
|
||||
$('#contentFrom_files').val('');
|
||||
$('#public').attr('checked', false);
|
||||
$('#contentForm_message_contenteditable').html('<?php echo Html::encode(Yii::t("ContentModule.widgets_views_contentForm", "What's on your mind?")); ?>');
|
||||
$('#contentForm_message_contenteditable').addClass('atwho-placeholder');
|
||||
|
||||
$('#contentFormBody').find('.atwho-input').trigger('clear');
|
||||
|
||||
// Notify FileUploadButtonWidget to clear (by providing uploaderId)
|
||||
resetUploader('contentFormFiles');
|
||||
} else {
|
||||
$('#contentFormError').show();
|
||||
$.each(response.errors, function (fieldName, errorMessage) {
|
||||
// Mark Fields as Error
|
||||
fieldId = 'contentForm_' + fieldName;
|
||||
$('#' + fieldId).addClass('error');
|
||||
$.each(errorMessage, function (key, msg) {
|
||||
$('#contentFormError').append('<li><i class=\"icon-warning-sign\"></i> ' + msg + '</li>');
|
||||
});
|
||||
});
|
||||
}
|
||||
$('.contentForm_options .btn').show();
|
||||
$('#postform-loader').addClass('hidden');
|
||||
}
|
||||
</script>
|
||||
<div class="clearFloats"></div>
|
@ -89,8 +89,10 @@ $container = $object->content->container;
|
||||
<?php endif; ?>
|
||||
<?php echo $content; ?>
|
||||
</div>
|
||||
|
||||
<?php echo \humhub\modules\content\widgets\WallEntryAddons::widget(['object' => $object]); ?>
|
||||
<div class="clearfix">
|
||||
<span class="entry-loader"></span>
|
||||
<?php echo \humhub\modules\content\widgets\WallEntryAddons::widget(['object' => $object]); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
@ -1,11 +0,0 @@
|
||||
humhub.modules.post = (function(module, $) {
|
||||
humhub.modules.registerAjaxHandler('humhub.modules.post.create', function(json) {
|
||||
humhub.modules.stream.getStream();
|
||||
}, function(error) {
|
||||
if(error)
|
||||
alert(error);
|
||||
});
|
||||
return module;
|
||||
|
||||
humhub.ui.richtext.register()
|
||||
})(humhub.modules.post || {}, $);
|
@ -24,24 +24,10 @@ use humhub\compat\CActiveForm;
|
||||
'object' => $post
|
||||
));
|
||||
?>
|
||||
|
||||
<?php
|
||||
echo \humhub\widgets\AjaxButton::widget([
|
||||
'label' => Yii::t('PostModule.views_edit', 'Save'),
|
||||
'ajaxOptions' => [
|
||||
'type' => 'POST',
|
||||
'beforeSend' => new yii\web\JsExpression('function(html){ $("#post_input_' . $post->id . '_contenteditable").hide(); showLoader("' . $post->id . '"); }'),
|
||||
'success' => new yii\web\JsExpression('function(html){ $(".wall_' . $post->getUniqueId() . '").replaceWith(html); }'),
|
||||
'statusCode' => ['400' => new yii\web\JsExpression('function(xhr) { $("#post_edit_'. $post->id.'").replaceWith(xhr.responseText); }')],
|
||||
'url' => $post->content->container->createUrl('/post/post/edit', ['id' => $post->id]),
|
||||
],
|
||||
'htmlOptions' => [
|
||||
'class' => 'btn btn-default btn-sm btn-comment-submit',
|
||||
'id' => 'post_edit_post_' . $post->id,
|
||||
'type' => 'submit'
|
||||
]
|
||||
]);
|
||||
?>
|
||||
<button type="submit" class="btn btn-default btn-sm btn-comment-submit" data-action-click="editSubmit" data-action-url="<?= $post->content->container->createUrl('/post/post/edit', ['id' => $post->id]) ?>">
|
||||
<?= Yii::t('PostModule.views_edit', 'Save') ?>
|
||||
</button>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
47
protected/humhub/modules/post/widgets/CreateForm.php
Normal file
47
protected/humhub/modules/post/widgets/CreateForm.php
Normal file
@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\modules\post\widgets;
|
||||
|
||||
/**
|
||||
* This widget is used include the post form.
|
||||
* It normally should be placed above a steam.
|
||||
*
|
||||
* @since 0.5
|
||||
*/
|
||||
class Form extends \humhub\modules\content\widgets\WallCreateContentForm
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public $submitUrl = '/post/post/post';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function renderForm()
|
||||
{
|
||||
return $this->render('form', array());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
if (!$this->contentContainer->permissionManager->can(new \humhub\modules\post\permissions\CreatePost())) {
|
||||
return;
|
||||
}
|
||||
|
||||
return parent::run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
14
protected/humhub/modules/post/widgets/views/createForm.php
Normal file
14
protected/humhub/modules/post/widgets/views/createForm.php
Normal file
@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
use yii\helpers\Html;
|
||||
?>
|
||||
|
||||
<?php echo Html::textarea("message", '', array('id' => 'contentForm_message', 'class' => 'form-control autosize contentForm', 'rows' => '1', 'placeholder' => Yii::t("PostModule.widgets_views_postForm", "What's on your mind?"))); ?>
|
||||
|
||||
<?php
|
||||
|
||||
/* Modify textarea for mention input */
|
||||
echo \humhub\widgets\RichTextEditor::widget(array(
|
||||
'id' => 'contentForm_message',
|
||||
));
|
||||
?>
|
@ -57,6 +57,12 @@ abstract class Stream extends Action
|
||||
* @var string
|
||||
*/
|
||||
public $mode;
|
||||
|
||||
/**
|
||||
* Used to load single content entries.
|
||||
* @since 1.2
|
||||
*/
|
||||
public $contentId;
|
||||
|
||||
/**
|
||||
* First wall entry id to deliver
|
||||
@ -112,6 +118,8 @@ abstract class Stream extends Action
|
||||
|
||||
// Read parameters
|
||||
if (!Yii::$app->request->isConsoleRequest) {
|
||||
$this->contentId = Yii::$app->getRequest()->get('id');
|
||||
|
||||
$from = Yii::$app->getRequest()->get('from', 0);
|
||||
if ($from != 0) {
|
||||
$this->from = (int) $from;
|
||||
@ -131,10 +139,12 @@ abstract class Stream extends Action
|
||||
if ($limit != "" && $limit <= self::MAX_LIMIT) {
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
$mode = Yii::$app->getRequest()->get('mode', '');
|
||||
if ($mode != "" && ($mode == self::MODE_ACTIVITY || $mode == self::MODE_NORMAL)) {
|
||||
$this->mode = $mode;
|
||||
}
|
||||
|
||||
foreach (explode(',', Yii::$app->getRequest()->get('filters', "")) as $filter) {
|
||||
$this->filters[] = trim($filter);
|
||||
}
|
||||
@ -166,6 +176,11 @@ abstract class Stream extends Action
|
||||
} else {
|
||||
$this->activeQuery->andWhere(['!=', 'content.object_model', \humhub\modules\activity\models\Activity::className()]);
|
||||
}
|
||||
|
||||
if($this->contentId) {
|
||||
$this->activeQuery->andWhere(['content.id' => $this->contentId]);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup Sorting
|
||||
|
@ -16,11 +16,11 @@ class StreamAsset extends AssetBundle
|
||||
public $sourcePath = '@humhub/modules/stream/assets';
|
||||
public $css = [];
|
||||
public $js = [
|
||||
'js/humhub.stream.js'
|
||||
'js/humhub.stream.js',
|
||||
];
|
||||
|
||||
public $depends = [
|
||||
'humhub\assets\CoreApiAsset'
|
||||
'humhub\modules\content\assets\ContentAsset'
|
||||
];
|
||||
|
||||
}
|
||||
|
@ -9,42 +9,58 @@ humhub.initModule('stream', function (module, require, $) {
|
||||
var string = util.string;
|
||||
var client = require('client');
|
||||
var Content = require('content').Content;
|
||||
var Component = require('action').Component;
|
||||
var loader = require('ui.loader');
|
||||
var event = require('event');
|
||||
var log = require('log').module(module);
|
||||
|
||||
/**
|
||||
* Number of initial stream enteis loaded when stream is initialized.
|
||||
* @type Number
|
||||
*/
|
||||
var STREAM_INIT_COUNT = 8;
|
||||
|
||||
|
||||
/**
|
||||
* Number of stream entries loaded with each request (except initial request)
|
||||
* @type Number
|
||||
*/
|
||||
var STREAM_LOAD_COUNT = 4;
|
||||
|
||||
|
||||
/**
|
||||
* Set on the stream root node to identify a stream. The value of this data
|
||||
* attribute contains the stream url for loading new entries.
|
||||
* @type String
|
||||
*/
|
||||
var DATA_STREAM_SELECTOR = '[data-stream]';
|
||||
|
||||
|
||||
/**
|
||||
* Number of stream entries loaded with each request (except initial request)
|
||||
* @type Number
|
||||
*/
|
||||
var DATA_WALL_STREAM_SELECTOR = '#wallStream';
|
||||
|
||||
/**
|
||||
* Set on a stream entry root node to identify stream-entries.
|
||||
* @type String
|
||||
*/
|
||||
var DATA_STREAM_ENTRY_SELECTOR = '[data-stream-entry]';
|
||||
|
||||
|
||||
/**
|
||||
* If a data-stream-contentid is set on the stream root only one entry will
|
||||
* be loaded. e.g. for permlinks
|
||||
* @type String
|
||||
*/
|
||||
var DATA_STREAM_CONTENTID = 'stream-contentid';
|
||||
|
||||
|
||||
//TODO: load streamUrl from config
|
||||
//TODO: readonly
|
||||
/**
|
||||
* If a data-stream-contentid is set on the stream root only one entry will
|
||||
* be loaded. e.g. for permlinks
|
||||
* @type String
|
||||
*/
|
||||
var DATA_STREAM_ENTRY_ID_SELECTOR = 'content-key';
|
||||
|
||||
|
||||
var streams = {};
|
||||
|
||||
/**
|
||||
* Represents an stream entry within a stream.
|
||||
@ -64,57 +80,192 @@ humhub.initModule('stream', function (module, require, $) {
|
||||
StreamEntry.prototype.delete = function () {
|
||||
var content = this.getContentComponent();
|
||||
if (content && content.delete) {
|
||||
//TODO: modalconfirm
|
||||
content.delete();
|
||||
} else {
|
||||
StreamEntry._super.delete.call(this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
StreamEntry.prototype.getContentComponent = function () {
|
||||
var children = this.children();
|
||||
return children.length ? children[0] : undefined;
|
||||
};
|
||||
|
||||
StreamEntry.prototype.reload = function () {
|
||||
getStream().reload(this);
|
||||
return getStream().reloadEntry(this);
|
||||
};
|
||||
|
||||
StreamEntry.prototype.edit = function () {
|
||||
//Search for data-content-edit-url on root.
|
||||
//Call this url with data-content-key
|
||||
//Trigger delete event
|
||||
StreamEntry.prototype.edit = function (evt) {
|
||||
var that = this;
|
||||
this.loader();
|
||||
client.get(evt.url, {
|
||||
dataType: 'html',
|
||||
success: function (response) {
|
||||
var $content = that.$.find('.content:first');
|
||||
var $oldContent = $content.clone();
|
||||
$content.replaceWith(response.html);
|
||||
that.$.data('oldContent', $oldContent);
|
||||
that.$.find('input[type="text"], textarea, [contenteditable="true"]').first().focus();
|
||||
that.unsetLoader();
|
||||
},
|
||||
error: function(e) {
|
||||
//TODO: handle error
|
||||
that.unsetLoader();
|
||||
}
|
||||
});
|
||||
|
||||
// Listen to click events outside of the stream entry and cancel edit.
|
||||
$('body').off('click.humhub:modules:stream:edit').on('click.humhub:modules:stream:edit', function (e) {
|
||||
if (!$(e.target).closest('[data-content-key="' + that.getKey() + '"]').length) {
|
||||
var $editContent = that.$.find('.content_edit:first');
|
||||
if ($editContent && that.$.data('oldContent')) {
|
||||
$editContent.replaceWith(that.$.data('oldContent'));
|
||||
that.$.data('oldContent', undefined);
|
||||
}
|
||||
$('body').off('click.humhub:modules:stream:edit');
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
StreamEntry.prototype.loader = function (selector) {
|
||||
//selector = selector || '.content:first';
|
||||
selector = selector || '.entry-loader';
|
||||
loader.set(this.$.find(selector), {
|
||||
'position': 'left',
|
||||
'size': '8px',
|
||||
'css': {
|
||||
'padding': '0px'
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
StreamEntry.prototype.unsetLoader = function (selector) {
|
||||
//selector = selector || '.content:first';
|
||||
selector = selector || '.entry-loader';
|
||||
loader.reset(this.$.find(selector));
|
||||
};
|
||||
|
||||
StreamEntry.prototype.editSubmit = function (evt) {
|
||||
var that = this;
|
||||
client.submit(evt.$form, {
|
||||
url: evt.url,
|
||||
dataType: 'html',
|
||||
beforeSend: function () {
|
||||
//that.loader('.content_edit:first');
|
||||
that.loader();
|
||||
},
|
||||
success: function (response) {
|
||||
that.$.html(response.html);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
StreamEntry.prototype.stick = function (evt) {
|
||||
var that = this;
|
||||
this.loader();
|
||||
var stream = that.getStream();
|
||||
client.post(evt.url).done(function (data) {
|
||||
if (data.success) {
|
||||
that.remove().then(function () {
|
||||
stream.loadEntry(that.getKey(), {'prepend': true});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
StreamEntry.prototype.unstick = function (evt) {
|
||||
this.loader();
|
||||
client.post(evt.url).done(function (data) {
|
||||
module.init();
|
||||
});
|
||||
};
|
||||
|
||||
StreamEntry.prototype.archive = function (evt) {
|
||||
var that = this;
|
||||
this.loader();
|
||||
client.post(evt.url).then(function (response) {
|
||||
if (response.success) {
|
||||
that.reload().then(function () {
|
||||
log.info(module.text('info.archive.success'), true);
|
||||
});
|
||||
}
|
||||
}).catch(function (e) {
|
||||
log.error(e, true);
|
||||
});
|
||||
};
|
||||
|
||||
StreamEntry.prototype.unarchive = function (evt) {
|
||||
var that = this;
|
||||
this.loader();
|
||||
client.post(evt.url).then(function (response) {
|
||||
if (response.success) {
|
||||
that.reload().then(function () {
|
||||
log.info(module.text('info.unarchive.success'), true);
|
||||
});
|
||||
}
|
||||
}).catch(function (e) {
|
||||
log.error('Unexpected error', e, true);
|
||||
});
|
||||
};
|
||||
|
||||
StreamEntry.prototype.getStream = function () {
|
||||
// Just return the parent stream component.
|
||||
return this.parent();
|
||||
};
|
||||
|
||||
/**
|
||||
* Stream implementation.
|
||||
* Generic Stream implementation.
|
||||
*
|
||||
* @param {type} container id or jQuery object of the stream container
|
||||
* @returns {undefined}
|
||||
*/
|
||||
var Stream = function (container) {
|
||||
Content.call(this, container);
|
||||
var Stream = function (container, cfg) {
|
||||
Component.call(this, container);
|
||||
this.cfg = this.initConfig(cfg);
|
||||
|
||||
//If a contentId is set on the stream root we will only show the single content
|
||||
//If a contentId is set on the stream, the root we will only show a single entry
|
||||
if (this.$.data(DATA_STREAM_CONTENTID)) {
|
||||
this.contentId = parseInt(this.$.data(DATA_STREAM_CONTENTID));
|
||||
}
|
||||
|
||||
this.$stream = this.$.find(".s2_stream");
|
||||
this.$stream = this.$;
|
||||
|
||||
//Cache some stream relevant data/nodes
|
||||
this.url = this.$.data('stream'); //TODO: set this in config instead of data field
|
||||
this.$loader = this.$stream.find(".streamLoader");
|
||||
this.$content = this.$stream.find('.s2_streamContent');
|
||||
this.$filter = $('.wallFilterPanel');
|
||||
this.url = this.$.data('stream');
|
||||
this.$loader = this.$stream.find(this.cfg['loaderSelector']);
|
||||
this.$content = this.$stream.find(this.cfg['contentSelector']);
|
||||
this.$filter = this.cfg['filterPanel'];
|
||||
|
||||
//TODO: make this configurable
|
||||
this.filters = [];
|
||||
this.sort = "c";
|
||||
};
|
||||
|
||||
object.inherits(Stream, Content);
|
||||
object.inherits(Stream, Component);
|
||||
|
||||
/**
|
||||
* Initializes the stream configuration with default values.
|
||||
*
|
||||
* @param {type} cfg
|
||||
* @returns {humhub_stream_L5.Stream.prototype.initConfig.cfg}
|
||||
*/
|
||||
Stream.prototype.initConfig = function (cfg) {
|
||||
cfg = cfg || {};
|
||||
cfg['filterPanel'] = cfg['filterPanel'] || $('<div></div>');
|
||||
cfg['loaderSelector'] = cfg['loaderSelector'] || ".streamLoader";
|
||||
cfg['filterSelector'] = cfg['filterSelector'] || ".wallFilterPanel";
|
||||
cfg['contentSelector'] = cfg['contentSelector'] || "[data-stream-content]";
|
||||
cfg['loadInitialCount'] = cfg['loadInitialCount'] || STREAM_INIT_COUNT;
|
||||
cfg['loadCount'] = cfg['loadCount'] || STREAM_LOAD_COUNT;
|
||||
cfg['streamEntryClass'] = cfg['streamEntryClass'] || StreamEntry;
|
||||
return cfg;
|
||||
};
|
||||
|
||||
/**
|
||||
* The stream itself does not provide any content actions.
|
||||
*
|
||||
* @returns {Array}
|
||||
*/
|
||||
Stream.prototype.getContentActions = function () {
|
||||
return [];
|
||||
};
|
||||
@ -129,128 +280,210 @@ humhub.initModule('stream', function (module, require, $) {
|
||||
Stream.prototype.init = function () {
|
||||
this.clear();
|
||||
this.$stream.show();
|
||||
|
||||
if (this.isShowSingleEntry()) {
|
||||
this.loadSingleEntry(this.contentId);
|
||||
this.loadEntry(this.contentId);
|
||||
} else {
|
||||
this.loadEntries(STREAM_INIT_COUNT).then(function() {
|
||||
this.loadEntries({'limit': this.cfg['loadInitialCount']}).then(function () {
|
||||
/**
|
||||
* TODO: REWRITE OLD INITPLUGINS!!!
|
||||
*/
|
||||
initPlugins();
|
||||
});
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears the stream content.
|
||||
*
|
||||
* @returns {undefined}
|
||||
*/
|
||||
Stream.prototype.clear = function () {
|
||||
this.lastEntryLoaded = false;
|
||||
this.readOnly = false;
|
||||
this.loading = false;
|
||||
this.$.find(".s2_streamContent").empty();
|
||||
this.$.find(".s2_stream").hide();
|
||||
this.$.find(".s2_single").hide();
|
||||
this.$.find(".streamLoader").hide();
|
||||
this.$.find(".emptyStreamMessage").hide();
|
||||
this.$.find(".emptyFilterStreamMessage").hide();
|
||||
this.$.find('.back_button_holder').hide();
|
||||
this.$content.empty();
|
||||
this.$stream.hide();
|
||||
//this.$.find(".s2_single").hide();
|
||||
this.hideLoader();
|
||||
this.$filter.hide();
|
||||
this.$.trigger('humhub:modules:stream:clear', this);
|
||||
};
|
||||
|
||||
Stream.prototype.loadSingleEntry = function (contentId) {
|
||||
this.$.find('.back_button_holder').show();
|
||||
this.loadEntries(1, (contentId + 1), '');
|
||||
/**
|
||||
* Loads a single stream entry by a given content id.
|
||||
*
|
||||
* @param {type} contentId
|
||||
* @returns {undefined}
|
||||
*/
|
||||
Stream.prototype.loadEntry = function (contentId, cfg) {
|
||||
cfg = cfg || {};
|
||||
cfg['contentId'] = contentId;
|
||||
|
||||
var that = this;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
that.loadEntries(cfg).then(function ($entryNode) {
|
||||
resolve($entryNode);
|
||||
}).catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Reloads a given entry either by providing the contentId or a StreamEntry instance.
|
||||
* This function returns a Promise instance.
|
||||
*
|
||||
* @param {string|StreamEntry} entry
|
||||
* @returns {Promise}
|
||||
*/
|
||||
Stream.prototype.reloadEntry = function (entry) {
|
||||
var that = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
entry = (entry instanceof StreamEntry) ? entry : that.getEntry(entry);
|
||||
entry = (object.isString(entry)) ? that.getEntry(entry) : entry;
|
||||
|
||||
if (!entry) {
|
||||
console.warn('Attempt to reload of non existent entry: ' + entry);
|
||||
reject();
|
||||
return;
|
||||
log.warn('Attempt to reload non existing entry');
|
||||
return reject();
|
||||
}
|
||||
|
||||
var contentId = entry.getKey();
|
||||
return that._load(1, (contentId + 1), '').then(function (response) {
|
||||
if (response.content[contentId]) {
|
||||
entry.replaceContent(response.content[contentId].output);
|
||||
that.loadEntry(contentId, {'preventInsert': true}).then(function ($entryNode) {
|
||||
if (!$entryNode || !$entryNode.length) {
|
||||
entry.remove();
|
||||
resolve(entry);
|
||||
} else {
|
||||
console.warn('Reload failed: ContentId not found in response: ' + contentId);
|
||||
reject();
|
||||
entry.$.fadeOut();
|
||||
entry.$.replaceWith($entryNode);
|
||||
$entryNode.fadeIn(function () {
|
||||
resolve(entry);
|
||||
});
|
||||
}
|
||||
|
||||
}, reject);
|
||||
});
|
||||
};
|
||||
|
||||
Stream.prototype.loadEntries = function (limit, from, filter, sort) {
|
||||
if (this.loading || this.lastEntryLoaded) {
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Loads new entries to a stream by the given stream settings.
|
||||
*
|
||||
* @param {type} limit
|
||||
* @param {type} from
|
||||
* @param {type} filter
|
||||
* @param {type} sort
|
||||
* @returns {Promise|undefined}
|
||||
*/
|
||||
Stream.prototype.loadEntries = function (cfg) {
|
||||
// Overwrite the default stream settings if provided
|
||||
cfg = this.initLoadConfig(cfg);
|
||||
|
||||
//Initialize loading process
|
||||
this.$loader.show();
|
||||
this.loading = true;
|
||||
|
||||
//Overwrite the stream settings if provided
|
||||
limit = limit || STREAM_LOAD_COUNT;
|
||||
from = from || this.getLastContentId();
|
||||
filter = filter || this.getFilterString();
|
||||
sort = sort || this.sort;
|
||||
this.$.trigger('humhub:modules:stream:beforeLoadEntries', [this, cfg]);
|
||||
|
||||
var that = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
that._load(limit, from, filter, sort).then(function (response) {
|
||||
that.$loader.hide();
|
||||
if (object.isEmpty(response.content)) {
|
||||
var $result;
|
||||
// Don't proceed if stream is already loading
|
||||
if (that.loading || that.lastEntryLoaded) {
|
||||
resolve();
|
||||
return;
|
||||
}
|
||||
|
||||
that.showLoader();
|
||||
that.loading = true;
|
||||
that._load(cfg).then(function (response) {
|
||||
that.hideLoader();
|
||||
|
||||
// If its not a single entry load and we get no content, we expect last entry is loaded
|
||||
// This may have to be change if we require to reload multiple elements.
|
||||
if (!cfg['contentId'] && object.isEmpty(response.content)) {
|
||||
that.lastEntryLoaded = true;
|
||||
$('#btn-load-more').hide();
|
||||
that.$.trigger('humhub:modules:stream:lastEntryLoaded');
|
||||
} else {
|
||||
that.lastEntryLoaded = response.isLast;
|
||||
that.appendEntries(response);
|
||||
$result = that.addEntries(response, cfg['prepend']);
|
||||
}
|
||||
|
||||
that.loading = false;
|
||||
that.onChange();
|
||||
resolve();
|
||||
that.$.trigger('humhub:modules:stream:afterLoadEntries', this);
|
||||
resolve($result);
|
||||
}).catch(function (err) {
|
||||
//TODO: handle error
|
||||
that.loading = false;
|
||||
that.$loader.hide();
|
||||
reject();
|
||||
that.hideLoader();
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
Stream.prototype._load = function (limit, from, filter, sort) {
|
||||
Stream.prototype.initLoadConfig = function (cfg) {
|
||||
cfg = cfg || {};
|
||||
if (!object.isDefined(cfg['contentId'])) {
|
||||
cfg['limit'] = object.isDefined(cfg['limit']) ? cfg['limit'] : this.loadCount;
|
||||
cfg['from'] = object.isDefined(cfg['from']) ? cfg['from'] : this.getLastContentId();
|
||||
cfg['sort'] = cfg['sort'] || this.sort;
|
||||
} else {
|
||||
cfg['limit'] = 1;
|
||||
}
|
||||
|
||||
cfg['filter'] = cfg['filter'] || this.getFilterString();
|
||||
|
||||
cfg['prepend'] = object.isDefined(cfg['prepend']) ? cfg['prepend'] : false;
|
||||
return cfg;
|
||||
}
|
||||
|
||||
Stream.prototype.showLoader = function () {
|
||||
loader.append(this.$content);
|
||||
};
|
||||
|
||||
Stream.prototype.hideLoader = function () {
|
||||
this.$content.find('.humhub-ui-loader').remove();
|
||||
};
|
||||
|
||||
Stream.prototype._load = function (cfg) {
|
||||
cfg = cfg || {}
|
||||
return client.ajax(this.url, {
|
||||
data: {
|
||||
filters: filter,
|
||||
sort: sort,
|
||||
from: from,
|
||||
limit: limit
|
||||
filters: cfg.filter,
|
||||
sort: cfg.sort,
|
||||
from: cfg.from,
|
||||
limit: cfg.limit,
|
||||
id: cfg.contentId
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the content id of the last entry loaded.
|
||||
* @returns {unresolved}
|
||||
*/
|
||||
Stream.prototype.getLastContentId = function () {
|
||||
var $lastEntry = this.$stream.find(DATA_STREAM_ENTRY_SELECTOR).last();
|
||||
if ($lastEntry.length) {
|
||||
return $lastEntry.data(DATA_STREAM_CONTENTID);
|
||||
return $lastEntry.data(DATA_STREAM_ENTRY_ID_SELECTOR);
|
||||
}
|
||||
};
|
||||
|
||||
Stream.prototype.prependEntry = function (response) {
|
||||
return this.$content.prepend(response.output);
|
||||
};
|
||||
|
||||
Stream.prototype.appendEntry = function (response) {
|
||||
return this.$content.append(response.output);
|
||||
Stream.prototype.prependEntry = function (html) {
|
||||
var $html = $(html).hide();
|
||||
this.$content.prepend($html);
|
||||
$html.fadeIn();
|
||||
};
|
||||
|
||||
Stream.prototype.appendEntries = function (response) {
|
||||
Stream.prototype.appendEntry = function (html) {
|
||||
var $html = $(html).hide();
|
||||
this.$content.append($html);
|
||||
$html.fadeIn();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Appends all entries of a given stream response to the stream content.
|
||||
*
|
||||
* @param {type} response
|
||||
* @returns {unresolved}
|
||||
*/
|
||||
Stream.prototype.addEntries = function (response, cfg) {
|
||||
var that = this;
|
||||
var result = '';
|
||||
$.each(response.contentOrder, function (i, key) {
|
||||
@ -260,20 +493,31 @@ humhub.initModule('stream', function (module, require, $) {
|
||||
}
|
||||
result += response.content[key].output;
|
||||
});
|
||||
return this.$content.append(result);
|
||||
|
||||
|
||||
var $result = $(result).hide();
|
||||
|
||||
if (cfg['preventInsert']) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
this.$.trigger('humhub:modules:stream:beforeAddEntries', [response, result]);
|
||||
|
||||
if (cfg['prepend']) {
|
||||
this.prependEntry($result);
|
||||
} else {
|
||||
this.appendEntry($result);
|
||||
}
|
||||
|
||||
this.$.trigger('humhub:modules:stream:afterAddEntries', [response, result]);
|
||||
$result.fadeIn('fast');
|
||||
return $result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Fired when new entries are shown
|
||||
*/
|
||||
Stream.prototype.onChange = function () {
|
||||
if (this.readOnly) {
|
||||
$('.wallReadOnlyHide').hide();
|
||||
$('.wallReadOnlyShow').show();
|
||||
} else {
|
||||
$('.wallReadOnlyShow').hide();
|
||||
}
|
||||
|
||||
var hasEntries = this.hasEntries();
|
||||
if (!hasEntries && !this.hasFilter()) {
|
||||
this.$.find('.emptyStreamMessage').show();
|
||||
@ -285,32 +529,57 @@ humhub.initModule('stream', function (module, require, $) {
|
||||
this.$.find('.emptyStreamMessage').hide();
|
||||
this.$.find('.emptyFilterStreamMessage').hide();
|
||||
}
|
||||
|
||||
this.$entryCache = this.getEntryNodes();
|
||||
|
||||
//TODO: fire global event
|
||||
this.$entryCache = this.getEntryNodes();
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the stream is single entry mode.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
Stream.prototype.isShowSingleEntry = function () {
|
||||
return object.isDefined(this.contentId);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if the stream has entries loaded.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
Stream.prototype.hasEntries = function () {
|
||||
return this.getEntryCount() > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the count of loaded stream entries.
|
||||
*
|
||||
* @returns {humhub_stream_L5.Stream.$.find.length}
|
||||
*/
|
||||
Stream.prototype.getEntryCount = function () {
|
||||
return this.$.find(DATA_STREAM_ENTRY_SELECTOR).length;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns all stream entry nodes.
|
||||
*
|
||||
* @returns {unresolved}
|
||||
*/
|
||||
Stream.prototype.getEntryNodes = function () {
|
||||
return this.$.find(DATA_STREAM_ENTRY_SELECTOR);
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if a stream has filter settings.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
Stream.prototype.hasFilter = function () {
|
||||
return this.filters.length > 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a filter string out of the filter array.
|
||||
* @returns {string}
|
||||
*/
|
||||
Stream.prototype.getFilterString = function () {
|
||||
var result = '';
|
||||
$.each(this.filters, function (i, filter) {
|
||||
@ -320,12 +589,24 @@ humhub.initModule('stream', function (module, require, $) {
|
||||
return string.cutsuffix(result, ',');
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds a given filterId to the filter array.
|
||||
*
|
||||
* @param {type} filterId
|
||||
* @returns {undefined}
|
||||
*/
|
||||
Stream.prototype.setFilter = function (filterId) {
|
||||
if (this.filters.indexOf(filterId) < 0) {
|
||||
this.filters.push(filterId);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clears a given filter.
|
||||
*
|
||||
* @param {type} filterId
|
||||
* @returns {undefined}
|
||||
*/
|
||||
Stream.prototype.unsetFilter = function (filterId) {
|
||||
var index = this.filters.indexOf(filterId);
|
||||
if (index > -1) {
|
||||
@ -333,29 +614,78 @@ humhub.initModule('stream', function (module, require, $) {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns a StreamEntry instance for a iven content id.
|
||||
* @param {type} key
|
||||
* @returns {humhub_stream_L5.StreamEntry}
|
||||
*/
|
||||
Stream.prototype.getEntry = function (key) {
|
||||
return new StreamEntry(this.$.find(DATA_STREAM_ENTRY_SELECTOR+'[data-content-key="' + key + '"]'));
|
||||
return new this.cfg.streamEntryClass(this.$.find(DATA_STREAM_ENTRY_SELECTOR + '[data-content-key="' + key + '"]'));
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new StreamEntry out of the given childNode.
|
||||
* @param {type} $childNode
|
||||
* @returns {humhub_stream_L5.StreamEntry}
|
||||
*/
|
||||
Stream.prototype.getEntryByNode = function ($childNode) {
|
||||
return new StreamEntry($childNode.closest(DATA_STREAM_ENTRY_SELECTOR));
|
||||
return new this.cfg.streamEntryClass($childNode.closest(DATA_STREAM_ENTRY_SELECTOR));
|
||||
};
|
||||
|
||||
var getStream = function () {
|
||||
if (!module.instance) {
|
||||
var $stream = $(DATA_STREAM_SELECTOR).first();
|
||||
module.instance = $stream.length ? new Stream($stream) : undefined;
|
||||
/**
|
||||
* Stream implementation for main wall streams.
|
||||
*
|
||||
* @param {type} container
|
||||
* @param {type} cfg
|
||||
* @returns {undefined}
|
||||
*/
|
||||
var WallStream = function (container, cfg) {
|
||||
cfg = cfg || {};
|
||||
cfg['filterPanel'] = $('.wallFilterPanel');
|
||||
Stream.call(this, container, cfg);
|
||||
|
||||
var that = this;
|
||||
this.$.on('humhub:modules:stream:clear', function () {
|
||||
that.$.find(".emptyStreamMessage").hide();
|
||||
that.$.find(".emptyFilterStreamMessage").hide();
|
||||
that.$.find('.back_button_holder').hide();
|
||||
});
|
||||
|
||||
this.$.on('humhub:modules:stream:afterAppendEntries', function (evt, stream) {
|
||||
if (that.isShowSingleEntry()) {
|
||||
that.$.find('.back_button_holder').show();
|
||||
}
|
||||
});
|
||||
|
||||
this.$.on('humhub:modules:stream:lastEntryLoaded', function () {
|
||||
$('#btn-load-more').hide();
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
object.inherits(WallStream, Stream);
|
||||
|
||||
var getStream = function ($selector) {
|
||||
$selector = $selector || DATA_WALL_STREAM_SELECTOR;
|
||||
if (!streams[$selector]) {
|
||||
var $stream = (!$selector) ? $(DATA_WALL_STREAM_SELECTOR) : $($selector).first();
|
||||
return streams[$selector] = $stream.length ? new WallStream($stream) : undefined;
|
||||
}
|
||||
return module.instance;
|
||||
return streams[$selector];
|
||||
};
|
||||
|
||||
var getEntry = function (id) {
|
||||
return module.getStream().getEntry(id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes wall stream
|
||||
* @returns {undefined}
|
||||
*/
|
||||
var init = function () {
|
||||
var stream = getStream();
|
||||
streams = {};
|
||||
|
||||
var stream = getStream();
|
||||
if (!stream) {
|
||||
console.log('Non-Stream Page!');
|
||||
return;
|
||||
@ -363,8 +693,14 @@ humhub.initModule('stream', function (module, require, $) {
|
||||
|
||||
stream.init();
|
||||
|
||||
var lastKey;
|
||||
event.on('humhub:modules:content:newEntry', function (evt, html) {
|
||||
stream.prependEntry(html);
|
||||
});
|
||||
|
||||
$(window).scroll(function () {
|
||||
if (stream.isShowSingleEntry()) {
|
||||
return;
|
||||
}
|
||||
var $window = $(window);
|
||||
var scrollTop = $window.scrollTop();
|
||||
var windowHeight = $window.height();
|
||||
@ -374,27 +710,32 @@ humhub.initModule('stream', function (module, require, $) {
|
||||
}
|
||||
}
|
||||
|
||||
// Defines our base y position for changing the current entry
|
||||
var yLimit = scrollTop + (windowHeight / 2);
|
||||
|
||||
// Get id of current scroll item
|
||||
//TODO: chache the entry nodes !
|
||||
var matchingNodes = stream.$entryCache.map(function () {
|
||||
var $this = $(this);
|
||||
if ($this.offset().top < yLimit) {
|
||||
return $this;
|
||||
}
|
||||
});
|
||||
|
||||
// Get the id of the current element
|
||||
var $current = matchingNodes[matchingNodes.length - 1];
|
||||
var currentKey = $current && $current.length ? $current.data('content-key') : "";
|
||||
|
||||
if (lastKey !== currentKey) {
|
||||
lastKey = currentKey;
|
||||
// Set/remove active class
|
||||
console.log(currentKey);
|
||||
}
|
||||
/*
|
||||
|
||||
This can be used to trace the currently visible entries
|
||||
|
||||
var lastKey;
|
||||
// Defines our base y position for changing the current entry
|
||||
var yLimit = scrollTop + (windowHeight / 2);
|
||||
|
||||
// Get id of current scroll item
|
||||
//TODO: chache the entry nodes !
|
||||
var matchingNodes = stream.$entryCache.map(function () {
|
||||
var $this = $(this);
|
||||
if ($this.offset().top < yLimit) {
|
||||
return $this;
|
||||
}
|
||||
});
|
||||
|
||||
// Get the id of the current element
|
||||
var $current = matchingNodes[matchingNodes.length - 1];
|
||||
var currentKey = $current && $current.length ? $current.data('content-key') : "";
|
||||
|
||||
if (lastKey !== currentKey) {
|
||||
lastKey = currentKey;
|
||||
// Set/remove active class
|
||||
}
|
||||
*/
|
||||
});
|
||||
|
||||
stream.$.on('click', '.singleBackLink', function () {
|
||||
@ -444,108 +785,14 @@ humhub.initModule('stream', function (module, require, $) {
|
||||
module.export({
|
||||
StreamEntry: StreamEntry,
|
||||
Stream: Stream,
|
||||
WallStream: WallStream,
|
||||
getStream: getStream,
|
||||
getEntry: getEntry,
|
||||
init: init
|
||||
});
|
||||
});
|
||||
|
||||
/* TODO:
|
||||
Stream.prototype.wallStick = function (url) {
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
type: 'post',
|
||||
url: url
|
||||
}).done(function (data) {
|
||||
if (data.success) {
|
||||
if (currentStream) {
|
||||
$.each(data.wallEntryIds, function (k, wallEntryId) {
|
||||
currentStream.deleteEntry(wallEntryId);
|
||||
currentStream.prependEntry(wallEntryId);
|
||||
});
|
||||
$('html, body').animate({scrollTop: 0}, 'slow');
|
||||
}
|
||||
} else {
|
||||
alert(data.errorMessage);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Stream.prototype.wallUnstick = function (url) {
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
type: 'post',
|
||||
url: url
|
||||
}).done(function (data) {
|
||||
if (data.success) {
|
||||
//Reload the whole stream, since we have to reorder the entries
|
||||
currentStream.showStream();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Click Handler for Archive Link of Wall Posts
|
||||
* (archiveLink.php)
|
||||
*
|
||||
* @param {type} className
|
||||
* @param {type} id
|
||||
|
||||
Stream.prototype.wallArchive = function (id) {
|
||||
|
||||
url = wallArchiveLinkUrl.replace('-id-', id);
|
||||
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
type: 'post',
|
||||
url: url
|
||||
}).done(function (data) {
|
||||
if (data.success) {
|
||||
if (currentStream) {
|
||||
$.each(data.wallEntryIds, function (k, wallEntryId) {
|
||||
//currentStream.reloadWallEntry(wallEntryId);
|
||||
// fade out post
|
||||
setInterval(fadeOut(), 1000);
|
||||
|
||||
function fadeOut() {
|
||||
// fade out current archived post
|
||||
$('#wallEntry_' + wallEntryId).fadeOut('slow');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Click Handler for Un Archive Link of Wall Posts
|
||||
* (archiveLink.php)
|
||||
*
|
||||
* @param {type} className
|
||||
* @param {type} id
|
||||
|
||||
Stream.prototype.wallUnarchive = function (id) {
|
||||
url = wallUnarchiveLinkUrl.replace('-id-', id);
|
||||
|
||||
$.ajax({
|
||||
dataType: "json",
|
||||
type: 'post',
|
||||
url: url
|
||||
}).done(function (data) {
|
||||
if (data.success) {
|
||||
if (currentStream) {
|
||||
$.each(data.wallEntryIds, function (k, wallEntryId) {
|
||||
currentStream.reloadWallEntry(wallEntryId);
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
/*
|
||||
module.StreamItem.prototype.highlightContent = function () {
|
||||
var $content = this.getContent();
|
||||
$content.addClass('highlight');
|
||||
|
@ -5,7 +5,18 @@ use yii\web\View;
|
||||
|
||||
\humhub\modules\stream\assets\StreamAsset::register($this);
|
||||
|
||||
$contentId = (int) Yii::$app->request->getQueryParam('wallEntryId');
|
||||
$this->registerJsConfig([
|
||||
'stream' => [
|
||||
'text' => [
|
||||
'info.archive.success' => Yii::t('ContentModule.widgets_views_stream', 'The content has been successfully archived.'),
|
||||
'info.unarchive.success' => Yii::t('ContentModule.widgets_views_stream', 'The content has been successfully unarchived.'),
|
||||
'info.stick.success' => Yii::t('ContentModule.widgets_views_stream', 'The content has been successfully sticked.'),
|
||||
'info.unstick.success' => Yii::t('ContentModule.widgets_views_stream', 'The content has been successfully unsticked.'),
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$contentId = (int) Yii::$app->request->getQueryParam('contentId');
|
||||
$contentIdData = ($contentId != "") ? 'data-stream-contentid="' . $contentId . '"' : '';
|
||||
|
||||
if (Yii::$app->settings->get('horImageScrollOnMobile'))
|
||||
@ -49,16 +60,15 @@ $this->registerJsVar('defaultStreamSort', ($defaultStreamSort != '') ? $defaultS
|
||||
|
||||
<!-- Stream content -->
|
||||
<div id="wallStream" data-stream="<?= $streamUrl ?>" <?= $contentIdData ?>
|
||||
data-action-component="humhub.modules.stream.Stream"
|
||||
data-action-component="stream.WallStream"
|
||||
data-content-delete-url="<?= Url::to(['/content/content/delete']) ?>">
|
||||
|
||||
<!-- DIV for a normal wall stream -->
|
||||
<div class="s2_stream" style="display:none">
|
||||
<div class="s2_stream">
|
||||
<div class="back_button_holder" style="display:none">
|
||||
<a href="#" class="singleBackLink btn btn-primary"><?php echo Yii::t('ContentModule.widgets_views_stream', 'Back to stream'); ?></a><br><br>
|
||||
</div>
|
||||
<div class="s2_streamContent"></div>
|
||||
<?php echo \humhub\widgets\LoaderWidget::widget(['cssClass' => 'streamLoader']); ?>
|
||||
<div class="s2_streamContent" data-stream-content></div>
|
||||
|
||||
<div class="emptyStreamMessage" style="display:none;">
|
||||
<div class="<?php echo $this->context->messageStreamEmptyCss; ?>">
|
||||
|
@ -1,4 +1,4 @@
|
||||
<?php //[STAMP] 74c0c3a2840b2412882616390669c863
|
||||
<?php //[STAMP] 25c2b4e8b8fd2158213a3465a3ef3b60
|
||||
namespace user\_generated;
|
||||
|
||||
// This class was automatically generated by build task
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace tests\codeception\_support;
|
||||
|
||||
use Codeception\Module;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* This helper is used to populate the database with needed fixtures before any tests are run.
|
||||
@ -21,5 +22,17 @@ class WebHelper extends Module
|
||||
public function _beforeSuite($settings = [])
|
||||
{
|
||||
include __DIR__.'/../acceptance/_bootstrap.php';
|
||||
$this->initModules();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes modules defined in @tests/codeception/config/test.config.php
|
||||
* Note the config key in test.config.php is modules and not humhubModules!
|
||||
*/
|
||||
protected function initModules() {
|
||||
$cfg = \Codeception\Configuration::config();
|
||||
if(!empty($cfg['humhub_modules'])) {
|
||||
Yii::$app->moduleManager->enableModules($cfg['humhub_modules']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
29
protected/humhub/widgets/GlobalConfirmModal.php
Normal file
29
protected/humhub/widgets/GlobalConfirmModal.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\widgets;
|
||||
|
||||
/**
|
||||
* GlobalConfirmModal used as template for humhub.ui.modal.confirm actions.
|
||||
*
|
||||
* @see LayoutAddons
|
||||
* @author buddha
|
||||
* @since 1.2
|
||||
*/
|
||||
class GlobalConfirmModal extends \yii\base\Widget
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
return $this->render('globalConfirmModal');
|
||||
}
|
||||
|
||||
}
|
@ -9,6 +9,7 @@
|
||||
namespace humhub\widgets;
|
||||
|
||||
use yii\base\Widget;
|
||||
use Yii;
|
||||
|
||||
/**
|
||||
* AjaxButton is an replacement for Yii1 CHtml::AjaxButton
|
||||
@ -17,9 +18,39 @@ use yii\base\Widget;
|
||||
*/
|
||||
class JSConfig extends Widget
|
||||
{
|
||||
|
||||
public function run()
|
||||
{
|
||||
return $this->render('jsConfig');
|
||||
$this->getView()->registerJsConfig(
|
||||
[
|
||||
'action' => [
|
||||
'text' => [
|
||||
'actionHandlerNotFound' => Yii::t('base', 'An error occured while handling your last action. (Handler not found).'),
|
||||
]
|
||||
],
|
||||
'ui.modal' => [
|
||||
'defaultConfirmHeader' => Yii::t('base', '<strong>Confirm</strong> Action'),
|
||||
'defaultConfirmBody' => Yii::t('base', 'Do you really want to perform this Action?'),
|
||||
'defaultConfirmText' => Yii::t('base', 'Confirm'),
|
||||
'defaultCancelText' => Yii::t('base', 'Cancel')
|
||||
],
|
||||
'log' => [
|
||||
'traceLevel' => (YII_DEBUG) ? 'DEBUG' : 'INFO',
|
||||
'text' => [
|
||||
'default.error' => Yii::t('base', 'An unexpected error occured. If this keeps happening, please contact a site administrator.'),
|
||||
'0' => Yii::t('base', 'An unexpected error occured. If this keeps happening, please contact a site administrator.'),
|
||||
'403' => Yii::t('base', 'You are not allowed to run this action.'),
|
||||
'500' => Yii::t('base', 'An unexpected server error occured. If this keeps happening, please contact a site administrator.')
|
||||
]
|
||||
],
|
||||
'ui.status' => [
|
||||
'showMore' => Yii::$app->user->isAdmin() || YII_DEBUG,
|
||||
'text' => [
|
||||
'showMore' => Yii::t('base', 'Show more'),
|
||||
'showLess' => Yii::t('base', 'Show less')
|
||||
]
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,9 +24,13 @@ class LayoutAddons extends BaseStack
|
||||
*/
|
||||
public function init()
|
||||
{
|
||||
|
||||
$this->addWidget(GlobalModal::className());
|
||||
$this->addWidget(GlobalConfirmModal::className());
|
||||
$this->addWidget(\humhub\modules\tour\widgets\Tour::className());
|
||||
$this->addWidget(\humhub\modules\admin\widgets\TrackingWidget::className());
|
||||
$this->addWidget(LoaderWidget::className(), ['show' => false, 'id' => "humhub-ui-loader-default"]);
|
||||
$this->addWidget(StatusBar::className());
|
||||
|
||||
if (Yii::$app->params['enablePjax']) {
|
||||
$this->addWidget(Pjax::className());
|
||||
|
@ -43,6 +43,11 @@ class LoaderWidget extends \yii\base\Widget
|
||||
* @var string
|
||||
*/
|
||||
public $cssClass = "";
|
||||
|
||||
/**
|
||||
* defines if the loader is initially shown
|
||||
*/
|
||||
public $show = true;
|
||||
|
||||
/**
|
||||
* Displays / Run the Widgets
|
||||
@ -52,6 +57,7 @@ class LoaderWidget extends \yii\base\Widget
|
||||
return $this->render('loader', [
|
||||
'id' => $this->id,
|
||||
'cssClass' => $this->cssClass,
|
||||
'show' => $this->show
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,7 @@ class Modal extends Widget
|
||||
* @var type
|
||||
*/
|
||||
public $initialLoader;
|
||||
|
||||
public function run()
|
||||
{
|
||||
$dialogClass = 'modal-dialog';
|
||||
|
@ -29,6 +29,7 @@ namespace humhub\widgets;
|
||||
* @package humhub.widgets
|
||||
* @since 0.5
|
||||
* @author Andreas Strobel
|
||||
* @deprecated 1.2 Prefer using js api humhub.ui.modal.confirm.
|
||||
*/
|
||||
class ModalConfirm extends \yii\base\Widget
|
||||
{
|
||||
|
29
protected/humhub/widgets/StatusBar.php
Normal file
29
protected/humhub/widgets/StatusBar.php
Normal file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @link https://www.humhub.org/
|
||||
* @copyright Copyright (c) 2016 HumHub GmbH & Co. KG
|
||||
* @license https://www.humhub.com/licences
|
||||
*/
|
||||
|
||||
namespace humhub\widgets;
|
||||
|
||||
/**
|
||||
* StatusBar for user feedback (error/warning/info).
|
||||
*
|
||||
* @see LayoutAddons
|
||||
* @author buddha
|
||||
* @since 1.2
|
||||
*/
|
||||
class StatusBar extends \yii\base\Widget
|
||||
{
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
return $this->render('statusBar');
|
||||
}
|
||||
|
||||
}
|
@ -1,19 +1,10 @@
|
||||
<!-- check if flash message exists -->
|
||||
<?php if(Yii::$app->getSession()->hasFlash('data-saved')): ?>
|
||||
|
||||
<!-- <span> element to display the message -->
|
||||
<span class="data-saved"><i class="fa fa-check-circle"></i> <?php echo Yii::$app->getSession()->getFlash('data-saved'); ?></span>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
/* animate the flash message */
|
||||
$('.data-saved').hide();
|
||||
$('.data-saved').fadeIn('slow', function() {
|
||||
$('.data-saved').delay(1000).fadeOut('slow', function() {
|
||||
$(this).remove();
|
||||
});
|
||||
$(function() {
|
||||
humhub.modules.log.success('<?php echo Yii::$app->getSession()->getFlash('data-saved'); ?>', true);
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
<?php endif; ?>
|
||||
|
11
protected/humhub/widgets/views/globalConfirmModal.php
Normal file
11
protected/humhub/widgets/views/globalConfirmModal.php
Normal file
@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
echo \humhub\widgets\Modal::widget([
|
||||
'id' => 'globalModalConfirm',
|
||||
'size' => 'extra-small',
|
||||
'centerText' => true,
|
||||
'animation' => 'pulse',
|
||||
'footer' => '<button data-modal-cancel data-modal-close class="btn btn-primary"></button><button data-modal-confirm data-modal-close class="btn btn-primary"></button>'
|
||||
]);
|
||||
|
||||
?>
|
@ -1,3 +1,4 @@
|
||||
<?php //Todo: use base Modal widget ?>
|
||||
<div class="modal" id="globalModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
|
@ -1,16 +0,0 @@
|
||||
<script type="text/javascript">
|
||||
humhub.config.set({
|
||||
'ui.modal': {
|
||||
'defaultConfirmHeader': '<?= Yii::t('base', '<strong>Confirm</strong> Action') ?>',
|
||||
'defaultConfirmBody': '<?=Yii::t('base', 'Do you really want to perform this Action?') ?>',
|
||||
'defaultConfirmText': '<?=Yii::t('base', 'Confirm') ?>',
|
||||
'defaultCancelText': '<?=Yii::t('base', 'Cancel') ?>'
|
||||
}
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div id="<?php echo $id; ?>" class="loader <?php echo $cssClass; ?>">
|
||||
<div id="<?php echo $id; ?>" class="loader humhub-ui-loader <?php echo $cssClass; ?>" <?php if(isset($show) && !$show) : ?> style="display:none;" <?php endif; ?>>
|
||||
<div class="sk-spinner sk-spinner-three-bounce">
|
||||
<div class="sk-bounce1"></div>
|
||||
<div class="sk-bounce2"></div>
|
||||
|
5
protected/humhub/widgets/views/statusBar.php
Normal file
5
protected/humhub/widgets/views/statusBar.php
Normal file
@ -0,0 +1,5 @@
|
||||
<div id="status-bar" style="display:none;">
|
||||
<div class="status-bar-body">
|
||||
<div class="status-bar-content"></div>
|
||||
</div>
|
||||
</div>
|
File diff suppressed because one or more lines are too long
@ -3030,8 +3030,92 @@ img.bounceIn {
|
||||
background: lighten(@info, 25%) !important;
|
||||
}
|
||||
|
||||
|
||||
#nprogress .bar {
|
||||
height:2px;
|
||||
background: @info;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Statusbar
|
||||
// --------------------------------------------------
|
||||
|
||||
#status-bar {
|
||||
|
||||
}
|
||||
|
||||
.status-bar-body {
|
||||
color: white;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.7);
|
||||
text-align: center;
|
||||
padding: 20px;
|
||||
z-index: 9999999;
|
||||
bottom: 0px;
|
||||
display: block;
|
||||
line-height:20px;
|
||||
}
|
||||
|
||||
.status-bar-close {
|
||||
color:white;
|
||||
fonfont-weight:bold;
|
||||
font-size:21px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.status-bar-close:hover {
|
||||
color:white;
|
||||
}
|
||||
|
||||
.status-bar-close i {
|
||||
vertical-align:top !important;
|
||||
padding-top:3px;
|
||||
}
|
||||
|
||||
.status-bar-content i {
|
||||
margin-right:10px;
|
||||
font-size:21px;
|
||||
vertical-align:middle;
|
||||
}
|
||||
|
||||
.status-bar-content .showMore {
|
||||
color: @info;
|
||||
margin-left:10px;
|
||||
font-size:0.7em;
|
||||
cursor:pointer;
|
||||
vertical-align:middle;
|
||||
white-space:nowrap;
|
||||
}
|
||||
|
||||
.status-bar-content .status-bar-details {
|
||||
text-align:left;
|
||||
font-size:0.7em;
|
||||
margin-top:20px;
|
||||
max-height:200px;
|
||||
overflow:auto;
|
||||
}
|
||||
|
||||
.status-bar-content span {
|
||||
vertical-align:middle;
|
||||
}
|
||||
|
||||
.status-bar-content i.error, .status-bar-content i.fatal {
|
||||
color:@danger;
|
||||
}
|
||||
|
||||
.status-bar-content i.warning {
|
||||
color:@warning;
|
||||
}
|
||||
|
||||
.status-bar-content i.info, .status-bar-content i.debug {
|
||||
color:@info;
|
||||
}
|
||||
|
||||
.status-bar-content i.success {
|
||||
color:#85CA2B;
|
||||
}
|
||||
|
||||
.entry-loader {
|
||||
float:right;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user