commit
e8e72aa910
15 changed files with 367 additions and 52 deletions
|
@ -26,6 +26,7 @@ use OCA\Files\Controller\ApiController;
|
|||
use OCP\AppFramework\App;
|
||||
use \OCA\Files\Service\TagService;
|
||||
use \OCP\IContainer;
|
||||
use OCA\Files\Controller\ViewController;
|
||||
|
||||
class Application extends App {
|
||||
public function __construct(array $urlParams=array()) {
|
||||
|
@ -48,6 +49,20 @@ class Application extends App {
|
|||
);
|
||||
});
|
||||
|
||||
$container->registerService('ViewController', function (IContainer $c) use ($server) {
|
||||
return new ViewController(
|
||||
$c->query('AppName'),
|
||||
$c->query('Request'),
|
||||
$server->getURLGenerator(),
|
||||
$server->getNavigationManager(),
|
||||
$c->query('L10N'),
|
||||
$server->getConfig(),
|
||||
$server->getEventDispatcher(),
|
||||
$server->getUserSession(),
|
||||
$server->getUserFolder()
|
||||
);
|
||||
});
|
||||
|
||||
/**
|
||||
* Core
|
||||
*/
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* @author Christoph Wurst <christoph@winzerhof-wurst.at>
|
||||
* @author Lukas Reschke <lukas@owncloud.com>
|
||||
* @author Thomas Müller <thomas.mueller@tmit.eu>
|
||||
* @author Vincent Petry <pvince81@owncloud.com>
|
||||
*
|
||||
* @copyright Copyright (c) 2016, ownCloud, Inc.
|
||||
* @license AGPL-3.0
|
||||
|
@ -26,6 +27,7 @@ namespace OCA\Files\Controller;
|
|||
use OC\AppFramework\Http\Request;
|
||||
use OCP\AppFramework\Controller;
|
||||
use OCP\AppFramework\Http\ContentSecurityPolicy;
|
||||
use OCP\AppFramework\Http\Response;
|
||||
use OCP\AppFramework\Http\RedirectResponse;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\IConfig;
|
||||
|
@ -35,6 +37,8 @@ use OCP\IRequest;
|
|||
use OCP\IURLGenerator;
|
||||
use OCP\IUserSession;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use OCP\AppFramework\Http\NotFoundResponse;
|
||||
use OCP\Files\Folder;
|
||||
|
||||
/**
|
||||
* Class ViewController
|
||||
|
@ -58,6 +62,8 @@ class ViewController extends Controller {
|
|||
protected $eventDispatcher;
|
||||
/** @var IUserSession */
|
||||
protected $userSession;
|
||||
/** @var \OCP\Files\Folder */
|
||||
protected $userFolder;
|
||||
|
||||
/**
|
||||
* @param string $appName
|
||||
|
@ -68,6 +74,7 @@ class ViewController extends Controller {
|
|||
* @param IConfig $config
|
||||
* @param EventDispatcherInterface $eventDispatcherInterface
|
||||
* @param IUserSession $userSession
|
||||
* @param Folder $userFolder
|
||||
*/
|
||||
public function __construct($appName,
|
||||
IRequest $request,
|
||||
|
@ -76,7 +83,9 @@ class ViewController extends Controller {
|
|||
IL10N $l10n,
|
||||
IConfig $config,
|
||||
EventDispatcherInterface $eventDispatcherInterface,
|
||||
IUserSession $userSession) {
|
||||
IUserSession $userSession,
|
||||
Folder $userFolder
|
||||
) {
|
||||
parent::__construct($appName, $request);
|
||||
$this->appName = $appName;
|
||||
$this->request = $request;
|
||||
|
@ -86,6 +95,7 @@ class ViewController extends Controller {
|
|||
$this->config = $config;
|
||||
$this->eventDispatcher = $eventDispatcherInterface;
|
||||
$this->userSession = $userSession;
|
||||
$this->userFolder = $userFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -124,10 +134,15 @@ class ViewController extends Controller {
|
|||
*
|
||||
* @param string $dir
|
||||
* @param string $view
|
||||
* @param string $fileid
|
||||
* @return TemplateResponse
|
||||
* @throws \OCP\Files\NotFoundException
|
||||
*/
|
||||
public function index($dir = '', $view = '') {
|
||||
public function index($dir = '', $view = '', $fileid = null) {
|
||||
if ($fileid !== null) {
|
||||
return $this->showFile($fileid);
|
||||
}
|
||||
|
||||
$nav = new \OCP\Template('files', 'appnavigation', '');
|
||||
|
||||
// Load the files we need
|
||||
|
@ -239,4 +254,33 @@ class ViewController extends Controller {
|
|||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects to the file list and highlight the given file id
|
||||
*
|
||||
* @param string $fileId file id to show
|
||||
* @return Response redirect response or not found response
|
||||
*
|
||||
* @NoCSRFRequired
|
||||
* @NoAdminRequired
|
||||
*/
|
||||
public function showFile($fileId) {
|
||||
$files = $this->userFolder->getById($fileId);
|
||||
$params = [];
|
||||
|
||||
if (!empty($files)) {
|
||||
$file = current($files);
|
||||
if ($file instanceof Folder) {
|
||||
// set the full path to enter the folder
|
||||
$params['dir'] = $this->userFolder->getRelativePath($file->getPath());
|
||||
} else {
|
||||
// set parent path as dir
|
||||
$params['dir'] = $this->userFolder->getRelativePath($file->getParent()->getPath());
|
||||
// and scroll to the entry
|
||||
$params['scrollto'] = $file->getName();
|
||||
}
|
||||
return new RedirectResponse($this->urlGenerator->linkToRoute('files.view.index', $params));
|
||||
}
|
||||
return new NotFoundResponse();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,19 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
#app-sidebar .mainFileInfoView .icon {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#app-sidebar .mainFileInfoView .permalink {
|
||||
margin-left: 10px;
|
||||
opacity: .5;
|
||||
}
|
||||
#app-sidebar .mainFileInfoView .permalink-field>input {
|
||||
clear: both;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
#app-sidebar .file-details-container {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
|
|
|
@ -174,6 +174,7 @@
|
|||
|
||||
// detect when app changed their current directory
|
||||
$('#app-content').delegate('>div', 'changeDirectory', _.bind(this._onDirectoryChanged, this));
|
||||
$('#app-content').delegate('>div', 'afterChangeDirectory', _.bind(this._onAfterDirectoryChanged, this));
|
||||
$('#app-content').delegate('>div', 'changeViewerMode', _.bind(this._onChangeViewerMode, this));
|
||||
|
||||
$('#app-navigation').on('itemChanged', _.bind(this._onNavigationChanged, this));
|
||||
|
@ -224,7 +225,16 @@
|
|||
*/
|
||||
_onDirectoryChanged: function(e) {
|
||||
if (e.dir) {
|
||||
this._changeUrl(this.navigation.getActiveItem(), e.dir);
|
||||
this._changeUrl(this.navigation.getActiveItem(), e.dir, e.fileId);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Event handler for when an app notified that its directory changed
|
||||
*/
|
||||
_onAfterDirectoryChanged: function(e) {
|
||||
if (e.dir && e.fileId) {
|
||||
this._changeUrl(this.navigation.getActiveItem(), e.dir, e.fileId);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -260,15 +270,36 @@
|
|||
this.navigation.getActiveContainer().trigger(new $.Event('urlChanged', params));
|
||||
},
|
||||
|
||||
/**
|
||||
* Encode URL params into a string, except for the "dir" attribute
|
||||
* that gets encoded as path where "/" is not encoded
|
||||
*
|
||||
* @param {Object.<string>} params
|
||||
* @return {string} encoded params
|
||||
*/
|
||||
_makeUrlParams: function(params) {
|
||||
var dir = params.dir;
|
||||
delete params.dir;
|
||||
return 'dir=' + OC.encodePath(dir) + '&' + OC.buildQueryString(params);
|
||||
},
|
||||
|
||||
/**
|
||||
* Change the URL to point to the given dir and view
|
||||
*/
|
||||
_changeUrl: function(view, dir) {
|
||||
_changeUrl: function(view, dir, fileId) {
|
||||
var params = {dir: dir};
|
||||
if (view !== 'files') {
|
||||
params.view = view;
|
||||
} else if (fileId) {
|
||||
params.fileid = fileId;
|
||||
}
|
||||
var currentParams = OC.Util.History.parseUrlQuery();
|
||||
if (currentParams.dir === params.dir && currentParams.view === params.view && currentParams.fileid !== params.fileid) {
|
||||
// if only fileid changed or was added, replace instead of push
|
||||
OC.Util.History.replaceState(this._makeUrlParams(params));
|
||||
} else {
|
||||
OC.Util.History.pushState(this._makeUrlParams(params));
|
||||
}
|
||||
OC.Util.History.pushState(params);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
|
|
@ -619,7 +619,7 @@
|
|||
|
||||
this.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
|
||||
var dir = context.$file.attr('data-path') || context.fileList.getCurrentDirectory();
|
||||
context.fileList.changeDirectory(OC.joinPaths(dir, filename));
|
||||
context.fileList.changeDirectory(OC.joinPaths(dir, filename), true, false, parseInt(context.$file.attr('data-id'), 10));
|
||||
});
|
||||
|
||||
this.registerAction({
|
||||
|
|
|
@ -1362,19 +1362,20 @@
|
|||
return parseInt(this.$el.find('#permissions').val(), 10);
|
||||
},
|
||||
/**
|
||||
* @brief Changes the current directory and reload the file list.
|
||||
* @param targetDir target directory (non URL encoded)
|
||||
* @param changeUrl false if the URL must not be changed (defaults to true)
|
||||
* @param {boolean} force set to true to force changing directory
|
||||
* Changes the current directory and reload the file list.
|
||||
* @param {string} targetDir target directory (non URL encoded)
|
||||
* @param {boolean} [changeUrl=true] if the URL must not be changed (defaults to true)
|
||||
* @param {boolean} [force=false] set to true to force changing directory
|
||||
* @param {string} [fileId] optional file id, if known, to be appended in the URL
|
||||
*/
|
||||
changeDirectory: function(targetDir, changeUrl, force) {
|
||||
changeDirectory: function(targetDir, changeUrl, force, fileId) {
|
||||
var self = this;
|
||||
var currentDir = this.getCurrentDirectory();
|
||||
targetDir = targetDir || '/';
|
||||
if (!force && currentDir === targetDir) {
|
||||
return;
|
||||
}
|
||||
this._setCurrentDir(targetDir, changeUrl);
|
||||
this._setCurrentDir(targetDir, changeUrl, fileId);
|
||||
this.reload().then(function(success){
|
||||
if (!success) {
|
||||
self.changeDirectory(currentDir, true);
|
||||
|
@ -1389,8 +1390,9 @@
|
|||
* Sets the current directory name and updates the breadcrumb.
|
||||
* @param targetDir directory to display
|
||||
* @param changeUrl true to also update the URL, false otherwise (default)
|
||||
* @param {string} [fileId] file id
|
||||
*/
|
||||
_setCurrentDir: function(targetDir, changeUrl) {
|
||||
_setCurrentDir: function(targetDir, changeUrl, fileId) {
|
||||
targetDir = targetDir.replace(/\\/g, '/');
|
||||
var previousDir = this.getCurrentDirectory(),
|
||||
baseDir = OC.basename(targetDir);
|
||||
|
@ -1408,10 +1410,14 @@
|
|||
this.$el.find('#dir').val(targetDir);
|
||||
|
||||
if (changeUrl !== false) {
|
||||
this.$el.trigger(jQuery.Event('changeDirectory', {
|
||||
var params = {
|
||||
dir: targetDir,
|
||||
previousDir: previousDir
|
||||
}));
|
||||
};
|
||||
if (fileId) {
|
||||
params.fileId = fileId;
|
||||
}
|
||||
this.$el.trigger(jQuery.Event('changeDirectory', params));
|
||||
}
|
||||
this.breadcrumb.setDirectory(this.getCurrentDirectory());
|
||||
},
|
||||
|
@ -1557,6 +1563,18 @@
|
|||
|
||||
result.sort(this._sortComparator);
|
||||
this.setFiles(result);
|
||||
|
||||
if (this.dirInfo) {
|
||||
var newFileId = this.dirInfo.id;
|
||||
// update fileid in URL
|
||||
var params = {
|
||||
dir: this.getCurrentDirectory()
|
||||
};
|
||||
if (newFileId) {
|
||||
params.fileId = newFileId;
|
||||
}
|
||||
this.$el.trigger(jQuery.Event('afterChangeDirectory', params));
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
|
|
|
@ -12,7 +12,13 @@
|
|||
var TEMPLATE =
|
||||
'<div class="thumbnailContainer"><a href="#" class="thumbnail action-default"><div class="stretcher"/></a></div>' +
|
||||
'<div class="file-details-container">' +
|
||||
'<div class="fileName"><h3 title="{{name}}" class="ellipsis">{{name}}</h3></div>' +
|
||||
'<div class="fileName">' +
|
||||
'<h3 title="{{name}}" class="ellipsis">{{name}}</h3>' +
|
||||
'<a class="permalink" href="{{permalink}}" title="{{permalinkTitle}}">' +
|
||||
'<span class="icon icon-public"></span>' +
|
||||
'<span class="hidden-visually">{{permalinkTitle}}</span>' +
|
||||
'</a>' +
|
||||
'</div>' +
|
||||
' <div class="file-details ellipsis">' +
|
||||
' <a href="#" ' +
|
||||
' class="action action-favorite favorite">' +
|
||||
|
@ -20,6 +26,9 @@
|
|||
' </a>' +
|
||||
' {{#if hasSize}}<span class="size" title="{{altSize}}">{{size}}</span>, {{/if}}<span class="date" title="{{altDate}}">{{date}}</span>' +
|
||||
' </div>' +
|
||||
'</div>' +
|
||||
'<div class="hidden permalink-field">' +
|
||||
'<input type="text" value="{{permalink}}" placeholder="{{permalinkTitle}}" readonly="readonly"/>' +
|
||||
'</div>';
|
||||
|
||||
/**
|
||||
|
@ -50,7 +59,9 @@
|
|||
|
||||
events: {
|
||||
'click a.action-favorite': '_onClickFavorite',
|
||||
'click a.action-default': '_onClickDefaultAction'
|
||||
'click a.action-default': '_onClickDefaultAction',
|
||||
'click a.permalink': '_onClickPermalink',
|
||||
'focus .permalink-field>input': '_onFocusPermalink'
|
||||
},
|
||||
|
||||
template: function(data) {
|
||||
|
@ -72,6 +83,20 @@
|
|||
}
|
||||
},
|
||||
|
||||
_onClickPermalink: function() {
|
||||
var $row = this.$('.permalink-field');
|
||||
$row.toggleClass('hidden');
|
||||
if (!$row.hasClass('hidden')) {
|
||||
$row.find('>input').focus();
|
||||
}
|
||||
// cancel click, user must right-click + copy or middle click
|
||||
return false;
|
||||
},
|
||||
|
||||
_onFocusPermalink: function() {
|
||||
this.$('.permalink-field>input').select();
|
||||
},
|
||||
|
||||
_onClickFavorite: function(event) {
|
||||
event.preventDefault();
|
||||
this._fileActions.triggerAction('Favorite', this.model, this._fileList);
|
||||
|
@ -87,6 +112,11 @@
|
|||
this.render();
|
||||
},
|
||||
|
||||
_makePermalink: function(fileId) {
|
||||
var baseUrl = OC.getProtocol() + '://' + OC.getHost();
|
||||
return baseUrl + OC.generateUrl('/f/{fileId}', {fileId: fileId});
|
||||
},
|
||||
|
||||
setFileInfo: function(fileInfo) {
|
||||
if (this.model) {
|
||||
this.model.off('change', this._onModelChanged, this);
|
||||
|
@ -118,7 +148,9 @@
|
|||
altDate: OC.Util.formatDate(this.model.get('mtime')),
|
||||
date: OC.Util.relativeModifiedDate(this.model.get('mtime')),
|
||||
starAltText: isFavorite ? t('files', 'Favorited') : t('files', 'Favorite'),
|
||||
starIcon: OC.imagePath('core', isFavorite ? 'actions/starred' : 'actions/star')
|
||||
starIcon: OC.imagePath('core', isFavorite ? 'actions/starred' : 'actions/star'),
|
||||
permalink: this._makePermalink(this.model.get('id')),
|
||||
permalinkTitle: t('files', 'Local link')
|
||||
}));
|
||||
|
||||
// TODO: we really need OC.Previews
|
||||
|
|
|
@ -36,6 +36,7 @@ use OCP\IL10N;
|
|||
use OCP\IConfig;
|
||||
use OCP\IUserSession;
|
||||
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
|
||||
use OCP\Files\Folder;
|
||||
|
||||
/**
|
||||
* Class ViewControllerTest
|
||||
|
@ -61,6 +62,8 @@ class ViewControllerTest extends TestCase {
|
|||
private $user;
|
||||
/** @var IUserSession */
|
||||
private $userSession;
|
||||
/** @var Folder */
|
||||
private $userFolder;
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
|
@ -75,6 +78,7 @@ class ViewControllerTest extends TestCase {
|
|||
$this->userSession->expects($this->any())
|
||||
->method('getUser')
|
||||
->will($this->returnValue($this->user));
|
||||
$this->userFolder = $this->getMock('\OCP\Files\Folder');
|
||||
$this->viewController = $this->getMockBuilder('\OCA\Files\Controller\ViewController')
|
||||
->setConstructorArgs([
|
||||
'files',
|
||||
|
@ -84,7 +88,8 @@ class ViewControllerTest extends TestCase {
|
|||
$this->l10n,
|
||||
$this->config,
|
||||
$this->eventDispatcher,
|
||||
$this->userSession
|
||||
$this->userSession,
|
||||
$this->userFolder
|
||||
])
|
||||
->setMethods([
|
||||
'getStorageInfo',
|
||||
|
@ -287,4 +292,100 @@ class ViewControllerTest extends TestCase {
|
|||
$expected->setContentSecurityPolicy($policy);
|
||||
$this->assertEquals($expected, $this->viewController->index('MyDir', 'MyView'));
|
||||
}
|
||||
|
||||
public function showFileMethodProvider() {
|
||||
return [
|
||||
[true],
|
||||
[false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider showFileMethodProvider
|
||||
*/
|
||||
public function testShowFileRouteWithFolder($useShowFile) {
|
||||
$node = $this->getMock('\OCP\Files\Folder');
|
||||
$node->expects($this->once())
|
||||
->method('getPath')
|
||||
->will($this->returnValue('/user/files/test/sub'));
|
||||
|
||||
$this->userFolder->expects($this->at(0))
|
||||
->method('getById')
|
||||
->with(123)
|
||||
->will($this->returnValue([$node]));
|
||||
$this->userFolder->expects($this->at(1))
|
||||
->method('getRelativePath')
|
||||
->with('/user/files/test/sub')
|
||||
->will($this->returnValue('/test/sub'));
|
||||
|
||||
$this->urlGenerator
|
||||
->expects($this->once())
|
||||
->method('linkToRoute')
|
||||
->with('files.view.index', ['dir' => '/test/sub'])
|
||||
->will($this->returnValue('/apps/files/?dir=/test/sub'));
|
||||
|
||||
$expected = new Http\RedirectResponse('/apps/files/?dir=/test/sub');
|
||||
if ($useShowFile) {
|
||||
$this->assertEquals($expected, $this->viewController->showFile(123));
|
||||
} else {
|
||||
$this->assertEquals($expected, $this->viewController->index('/whatever', '', '123'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider showFileMethodProvider
|
||||
*/
|
||||
public function testShowFileRouteWithFile($useShowFile) {
|
||||
$parentNode = $this->getMock('\OCP\Files\Folder');
|
||||
$parentNode->expects($this->once())
|
||||
->method('getPath')
|
||||
->will($this->returnValue('/user/files/test'));
|
||||
|
||||
$node = $this->getMock('\OCP\Files\File');
|
||||
$node->expects($this->once())
|
||||
->method('getParent')
|
||||
->will($this->returnValue($parentNode));
|
||||
$node->expects($this->once())
|
||||
->method('getName')
|
||||
->will($this->returnValue('somefile.txt'));
|
||||
|
||||
$this->userFolder->expects($this->at(0))
|
||||
->method('getById')
|
||||
->with(123)
|
||||
->will($this->returnValue([$node]));
|
||||
$this->userFolder->expects($this->at(1))
|
||||
->method('getRelativePath')
|
||||
->with('/user/files/test')
|
||||
->will($this->returnValue('/test'));
|
||||
|
||||
$this->urlGenerator
|
||||
->expects($this->once())
|
||||
->method('linkToRoute')
|
||||
->with('files.view.index', ['dir' => '/test', 'scrollto' => 'somefile.txt'])
|
||||
->will($this->returnValue('/apps/files/?dir=/test/sub&scrollto=somefile.txt'));
|
||||
|
||||
$expected = new Http\RedirectResponse('/apps/files/?dir=/test/sub&scrollto=somefile.txt');
|
||||
if ($useShowFile) {
|
||||
$this->assertEquals($expected, $this->viewController->showFile(123));
|
||||
} else {
|
||||
$this->assertEquals($expected, $this->viewController->index('/whatever', '', '123'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider showFileMethodProvider
|
||||
*/
|
||||
public function testShowFileRouteWithInvalidFileId($useShowFile) {
|
||||
$this->userFolder->expects($this->at(0))
|
||||
->method('getById')
|
||||
->with(123)
|
||||
->will($this->returnValue([]));
|
||||
|
||||
$expected = new Http\NotFoundResponse();
|
||||
if ($useShowFile) {
|
||||
$this->assertEquals($expected, $this->viewController->showFile(123));
|
||||
} else {
|
||||
$this->assertEquals($expected, $this->viewController->index('/whatever', '', '123'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
describe('OCA.Files.App tests', function() {
|
||||
var App = OCA.Files.App;
|
||||
var pushStateStub;
|
||||
var replaceStateStub;
|
||||
var parseUrlQueryStub;
|
||||
var oldLegacyFileActions;
|
||||
|
||||
|
@ -48,6 +49,7 @@ describe('OCA.Files.App tests', function() {
|
|||
OCA.Files.fileActions = new OCA.Files.FileActions();
|
||||
|
||||
pushStateStub = sinon.stub(OC.Util.History, 'pushState');
|
||||
replaceStateStub = sinon.stub(OC.Util.History, 'replaceState');
|
||||
parseUrlQueryStub = sinon.stub(OC.Util.History, 'parseUrlQuery');
|
||||
parseUrlQueryStub.returns({});
|
||||
|
||||
|
@ -59,6 +61,7 @@ describe('OCA.Files.App tests', function() {
|
|||
window.FileActions = oldLegacyFileActions;
|
||||
|
||||
pushStateStub.restore();
|
||||
replaceStateStub.restore();
|
||||
parseUrlQueryStub.restore();
|
||||
});
|
||||
|
||||
|
@ -119,18 +122,39 @@ describe('OCA.Files.App tests', function() {
|
|||
|
||||
describe('URL handling', function() {
|
||||
it('pushes the state to the URL when current app changed directory', function() {
|
||||
$('#app-content-files').trigger(new $.Event('changeDirectory', {dir: 'subdir'}));
|
||||
$('#app-content-files').trigger(new $.Event('changeDirectory', {dir: 'sub dir'}));
|
||||
expect(pushStateStub.calledOnce).toEqual(true);
|
||||
expect(pushStateStub.getCall(0).args[0].dir).toEqual('subdir');
|
||||
expect(pushStateStub.getCall(0).args[0].view).not.toBeDefined();
|
||||
var params = OC.parseQueryString(pushStateStub.getCall(0).args[0]);
|
||||
expect(params.dir).toEqual('sub dir');
|
||||
expect(params.view).not.toBeDefined();
|
||||
|
||||
$('li[data-id=other]>a').click();
|
||||
pushStateStub.reset();
|
||||
|
||||
$('#app-content-other').trigger(new $.Event('changeDirectory', {dir: 'subdir'}));
|
||||
$('#app-content-other').trigger(new $.Event('changeDirectory', {dir: 'sub dir'}));
|
||||
expect(pushStateStub.calledOnce).toEqual(true);
|
||||
expect(pushStateStub.getCall(0).args[0].dir).toEqual('subdir');
|
||||
expect(pushStateStub.getCall(0).args[0].view).toEqual('other');
|
||||
params = OC.parseQueryString(pushStateStub.getCall(0).args[0]);
|
||||
expect(params.dir).toEqual('sub dir');
|
||||
expect(params.view).toEqual('other');
|
||||
});
|
||||
it('replaces the state to the URL when fileid is known', function() {
|
||||
$('#app-content-files').trigger(new $.Event('changeDirectory', {dir: 'sub dir'}));
|
||||
expect(pushStateStub.calledOnce).toEqual(true);
|
||||
var params = OC.parseQueryString(pushStateStub.getCall(0).args[0]);
|
||||
expect(params.dir).toEqual('sub dir');
|
||||
expect(params.view).not.toBeDefined();
|
||||
expect(replaceStateStub.notCalled).toEqual(true);
|
||||
|
||||
parseUrlQueryStub.returns({dir: 'sub dir'});
|
||||
|
||||
$('#app-content-files').trigger(new $.Event('afterChangeDirectory', {dir: 'sub dir', fileId: 123}));
|
||||
|
||||
expect(pushStateStub.calledOnce).toEqual(true);
|
||||
expect(replaceStateStub.calledOnce).toEqual(true);
|
||||
params = OC.parseQueryString(replaceStateStub.getCall(0).args[0]);
|
||||
expect(params.dir).toEqual('sub dir');
|
||||
expect(params.view).not.toBeDefined();
|
||||
expect(params.fileid).toEqual('123');
|
||||
});
|
||||
describe('onpopstate', function() {
|
||||
it('sends "urlChanged" event to current app', function() {
|
||||
|
|
|
@ -1358,6 +1358,15 @@ describe('OCA.Files.FileList tests', function() {
|
|||
expect(handler.calledOnce).toEqual(true);
|
||||
expect(handler.getCall(0).args[0].dir).toEqual('/somedir');
|
||||
});
|
||||
it('triggers "afterChangeDirectory" event with fileid after changing directory', function() {
|
||||
var handler = sinon.stub();
|
||||
$('#app-content-files').on('afterChangeDirectory', handler);
|
||||
fileList.changeDirectory('/somedir');
|
||||
deferredList.resolve(200, [testRoot].concat(testFiles));
|
||||
expect(handler.calledOnce).toEqual(true);
|
||||
expect(handler.getCall(0).args[0].dir).toEqual('/somedir');
|
||||
expect(handler.getCall(0).args[0].fileId).toEqual(99);
|
||||
});
|
||||
it('changes the directory when receiving "urlChanged" event', function() {
|
||||
$('#app-content-files').trigger(new $.Event('urlChanged', {view: 'files', dir: '/somedir'}));
|
||||
expect(fileList.getCurrentDirectory()).toEqual('/somedir');
|
||||
|
|
|
@ -62,6 +62,11 @@ describe('OCA.Files.MainFileInfoDetailView tests', function() {
|
|||
expect(view.$el.find('.date').attr('title')).toEqual(dateExpected);
|
||||
clock.restore();
|
||||
});
|
||||
it('displays permalink', function() {
|
||||
view.setFileInfo(testFileInfo);
|
||||
expect(view.$el.find('.permalink').attr('href'))
|
||||
.toEqual(OC.getProtocol() + '://' + OC.getHost() + OC.generateUrl('/f/5'));
|
||||
});
|
||||
it('displays favorite icon', function() {
|
||||
testFileInfo.set('tags', [OC.TAG_FAVORITE]);
|
||||
view.setFileInfo(testFileInfo);
|
||||
|
|
|
@ -2050,8 +2050,9 @@ OC.Util.History = {
|
|||
*
|
||||
* @param params to append to the URL, can be either a string
|
||||
* or a map
|
||||
* @param {boolean} [replace=false] whether to replace instead of pushing
|
||||
*/
|
||||
pushState: function(params) {
|
||||
_pushState: function(params, replace) {
|
||||
var strParams;
|
||||
if (typeof(params) === 'string') {
|
||||
strParams = params;
|
||||
|
@ -2061,7 +2062,11 @@ OC.Util.History = {
|
|||
}
|
||||
if (window.history.pushState) {
|
||||
var url = location.pathname + '?' + strParams;
|
||||
window.history.pushState(params, '', url);
|
||||
if (replace) {
|
||||
window.history.replaceState(params, '', url);
|
||||
} else {
|
||||
window.history.pushState(params, '', url);
|
||||
}
|
||||
}
|
||||
// use URL hash for IE8
|
||||
else {
|
||||
|
@ -2072,6 +2077,32 @@ OC.Util.History = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Push the current URL parameters to the history stack
|
||||
* and change the visible URL.
|
||||
* Note: this includes a workaround for IE8/IE9 that uses
|
||||
* the hash part instead of the search part.
|
||||
*
|
||||
* @param params to append to the URL, can be either a string
|
||||
* or a map
|
||||
*/
|
||||
pushState: function(params) {
|
||||
return this._pushState(params, false);
|
||||
},
|
||||
|
||||
/**
|
||||
* Push the current URL parameters to the history stack
|
||||
* and change the visible URL.
|
||||
* Note: this includes a workaround for IE8/IE9 that uses
|
||||
* the hash part instead of the search part.
|
||||
*
|
||||
* @param params to append to the URL, can be either a string
|
||||
* or a map
|
||||
*/
|
||||
replaceState: function(params) {
|
||||
return this._pushState(params, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Add a popstate handler
|
||||
*
|
||||
|
@ -2129,7 +2160,12 @@ OC.Util.History = {
|
|||
if (!this._handlers.length) {
|
||||
return;
|
||||
}
|
||||
params = (e && e.state) || this.parseUrlQuery() || {};
|
||||
params = (e && e.state);
|
||||
if (_.isString(params)) {
|
||||
params = OC.parseQueryString(params);
|
||||
} else if (!params) {
|
||||
params = this.parseUrlQuery() || {};
|
||||
}
|
||||
for (var i = 0; i < this._handlers.length; i++) {
|
||||
this._handlers[i](params);
|
||||
}
|
||||
|
|
|
@ -108,6 +108,12 @@ $this->create('core_ajax_preview', '/core/preview.png')
|
|||
$this->create('core_ajax_update', '/core/ajax/update.php')
|
||||
->actionInclude('core/ajax/update.php');
|
||||
|
||||
// File routes
|
||||
$this->create('files.viewcontroller.showFile', '/f/{fileId}')->action(function($urlParams) {
|
||||
$app = new \OCA\Files\AppInfo\Application($urlParams);
|
||||
$app->dispatch('ViewController', 'showFile');
|
||||
});
|
||||
|
||||
// Sharing routes
|
||||
$this->create('files_sharing.sharecontroller.showShare', '/s/{token}')->action(function($urlParams) {
|
||||
$app = new \OCA\Files_Sharing\AppInfo\Application($urlParams);
|
||||
|
|
|
@ -119,27 +119,9 @@ class MailNotifications {
|
|||
}
|
||||
}
|
||||
|
||||
// Link to folder, or root folder if a file
|
||||
|
||||
if ($itemType === 'folder') {
|
||||
$args = array(
|
||||
'dir' => $filename,
|
||||
);
|
||||
} else if (strpos($filename, '/')) {
|
||||
$args = array(
|
||||
'dir' => '/' . dirname($filename),
|
||||
'scrollto' => basename($filename),
|
||||
);
|
||||
} else {
|
||||
$args = array(
|
||||
'dir' => '/',
|
||||
'scrollto' => $filename,
|
||||
);
|
||||
}
|
||||
|
||||
$link = $this->urlGenerator->linkToRouteAbsolute(
|
||||
'files.view.index',
|
||||
$args
|
||||
'files.viewcontroller.showFile',
|
||||
['fileId' => $items[0]['item_source']]
|
||||
);
|
||||
|
||||
list($htmlBody, $textBody) = $this->createMailBody($filename, $link, $expiration, 'internal');
|
||||
|
|
|
@ -222,7 +222,7 @@ class MailNotificationsTest extends \Test\TestCase {
|
|||
$mailNotifications->method('getItemSharedWithUser')
|
||||
->withAnyParameters()
|
||||
->willReturn([
|
||||
['file_target' => '/welcome.txt']
|
||||
['file_target' => '/welcome.txt', 'item_source' => 123],
|
||||
]);
|
||||
|
||||
$recipient = $this->getMockBuilder('\OCP\IUser')
|
||||
|
@ -239,10 +239,9 @@ class MailNotificationsTest extends \Test\TestCase {
|
|||
$this->urlGenerator->expects($this->once())
|
||||
->method('linkToRouteAbsolute')
|
||||
->with(
|
||||
$this->equalTo('files.view.index'),
|
||||
$this->equalTo('files.viewcontroller.showFile'),
|
||||
$this->equalTo([
|
||||
'dir' => '/',
|
||||
'scrollto' => 'welcome.txt'
|
||||
'fileId' => 123,
|
||||
])
|
||||
);
|
||||
|
||||
|
|
Loading…
Reference in a new issue