summaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-rw-r--r--apps/dav/l10n/es_CL.js10
-rw-r--r--apps/dav/l10n/es_CL.json10
-rw-r--r--apps/dav/l10n/eu.js61
-rw-r--r--apps/dav/l10n/eu.json59
-rw-r--r--apps/files/css/files.scss22
-rw-r--r--apps/files/img/add-color.pngbin4217 -> 302 bytes
-rw-r--r--apps/files/img/add-color.svg7
-rw-r--r--apps/files/img/delete.svg2
-rw-r--r--apps/files/img/share.svg2
-rw-r--r--apps/files/js/breadcrumb.js223
-rw-r--r--apps/files/js/filelist.js43
-rw-r--r--apps/files/js/files.js18
-rw-r--r--apps/files/l10n/da.js3
-rw-r--r--apps/files/l10n/da.json3
-rw-r--r--apps/files/l10n/el.js6
-rw-r--r--apps/files/l10n/el.json6
-rw-r--r--apps/files/l10n/es.js2
-rw-r--r--apps/files/l10n/es.json2
-rw-r--r--apps/files/l10n/es_CL.js3
-rw-r--r--apps/files/l10n/es_CL.json3
-rw-r--r--apps/files/l10n/es_MX.js2
-rw-r--r--apps/files/l10n/es_MX.json2
-rw-r--r--apps/files/l10n/fr.js1
-rw-r--r--apps/files/l10n/fr.json1
-rw-r--r--apps/files/l10n/nl.js3
-rw-r--r--apps/files/l10n/nl.json3
-rw-r--r--apps/files/tests/js/breadcrumbSpec.js245
-rw-r--r--apps/files/tests/js/filelistSpec.js8
-rw-r--r--apps/files_external/3rdparty/composer.json2
-rw-r--r--apps/files_external/3rdparty/composer.lock12
-rw-r--r--apps/files_external/3rdparty/composer/autoload_classmap.php3
-rw-r--r--apps/files_external/3rdparty/composer/autoload_static.php3
-rw-r--r--apps/files_external/3rdparty/composer/installed.json12
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/ErrorCodes.php4
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/Exception/Exception.php2
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidParameterException.php10
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/Exception/OutOfSpaceException.php11
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/Exception/RevisionMismatchException.php16
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/NativeState.php1
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/NotifyHandler.php17
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/Parser.php4
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/RawConnection.php64
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/Server.php1
-rw-r--r--apps/files_external/3rdparty/icewind/smb/src/Share.php11
-rw-r--r--apps/files_external/templates/settings.php4
-rw-r--r--apps/files_trashbin/tests/js/filelistSpec.js10
-rw-r--r--apps/theming/appinfo/info.xml2
-rw-r--r--apps/theming/l10n/es_CL.js1
-rw-r--r--apps/theming/l10n/es_CL.json1
-rw-r--r--apps/theming/l10n/ru.js1
-rw-r--r--apps/theming/l10n/ru.json1
-rw-r--r--apps/theming/lib/IconBuilder.php28
-rw-r--r--apps/theming/tests/IconBuilderTest.php21
-rw-r--r--apps/user_ldap/js/wizard/wizardTabElementary.js1
-rw-r--r--apps/user_ldap/js/wizard/wizardTabGeneric.js4
-rw-r--r--apps/user_ldap/l10n/es_CL.js1
-rw-r--r--apps/user_ldap/l10n/es_CL.json1
-rw-r--r--apps/user_ldap/l10n/ru.js1
-rw-r--r--apps/user_ldap/l10n/ru.json1
-rw-r--r--apps/user_ldap/lib/User/User.php3
-rw-r--r--apps/user_ldap/templates/part.wizardcontrols.php2
-rw-r--r--apps/user_ldap/tests/User/UserTest.php9
62 files changed, 716 insertions, 299 deletions
diff --git a/apps/dav/l10n/es_CL.js b/apps/dav/l10n/es_CL.js
index 433949bf30f..452cd6e77b5 100644
--- a/apps/dav/l10n/es_CL.js
+++ b/apps/dav/l10n/es_CL.js
@@ -41,6 +41,16 @@ OC.L10N.register(
"A calendar <strong>event</strong> was modified" : "Un <strong>evento</strong> de un calendario fue modificado",
"A calendar <strong>todo</strong> was modified" : "Un <strong>pendiente</strong> de un calendario fue modificado",
"Contact birthdays" : "Cumpleaños del contacto",
+ "Invitation canceled" : "Invitación cancelada",
+ "Hello %s," : "Hola %s,",
+ "The meeting »%s« with %s was canceled." : "La cita »%s« con %s fue cancelada.",
+ "Invitation updated" : "Invitación actualizada",
+ "The meeting »%s« with %s was updated." : "La reunión »%s« con %s ha sido actualizada.",
+ "%s invited you to »%s«" : "%s te ha invitado a »%s«",
+ "When:" : "Cuándo:",
+ "Where:" : "Dónde:",
+ "Description:" : "Descripción:",
+ "Link:" : "Enlace:",
"Contacts" : "Contactos",
"Technical details" : "Detalles técnicos",
"Remote Address: %s" : "Dirección remota: %s",
diff --git a/apps/dav/l10n/es_CL.json b/apps/dav/l10n/es_CL.json
index ea72915ea47..918fa4513bc 100644
--- a/apps/dav/l10n/es_CL.json
+++ b/apps/dav/l10n/es_CL.json
@@ -39,6 +39,16 @@
"A calendar <strong>event</strong> was modified" : "Un <strong>evento</strong> de un calendario fue modificado",
"A calendar <strong>todo</strong> was modified" : "Un <strong>pendiente</strong> de un calendario fue modificado",
"Contact birthdays" : "Cumpleaños del contacto",
+ "Invitation canceled" : "Invitación cancelada",
+ "Hello %s," : "Hola %s,",
+ "The meeting »%s« with %s was canceled." : "La cita »%s« con %s fue cancelada.",
+ "Invitation updated" : "Invitación actualizada",
+ "The meeting »%s« with %s was updated." : "La reunión »%s« con %s ha sido actualizada.",
+ "%s invited you to »%s«" : "%s te ha invitado a »%s«",
+ "When:" : "Cuándo:",
+ "Where:" : "Dónde:",
+ "Description:" : "Descripción:",
+ "Link:" : "Enlace:",
"Contacts" : "Contactos",
"Technical details" : "Detalles técnicos",
"Remote Address: %s" : "Dirección remota: %s",
diff --git a/apps/dav/l10n/eu.js b/apps/dav/l10n/eu.js
new file mode 100644
index 00000000000..d09ac2a7f3b
--- /dev/null
+++ b/apps/dav/l10n/eu.js
@@ -0,0 +1,61 @@
+OC.L10N.register(
+ "dav",
+ {
+ "Calendar" : "Egutegia",
+ "Todos" : "Egitekoak",
+ "Personal" : "Pertsonala",
+ "{actor} created calendar {calendar}" : "{actor}-k sortutako egutegia: {calendar}",
+ "You created calendar {calendar}" : "{calendar} egutegia sortu duzu",
+ "{actor} deleted calendar {calendar}" : "{actor}-k {calendar} egutegia borratu du",
+ "You deleted calendar {calendar}" : "{calendar} egutegia borratu duzu",
+ "{actor} updated calendar {calendar}" : "{actor} -k {calendar} egutegia eguneratu du",
+ "You updated calendar {calendar}" : "{calendar} egutegia eguneratu duzu ",
+ "{actor} shared calendar {calendar} with you" : "{actor} -k zurekin {calendar} egutegia partekatu du",
+ "You shared calendar {calendar} with {user}" : "{calendar} egutegia {user} erabiltzailearekin partekatu duzu",
+ "{actor} shared calendar {calendar} with {user}" : "{actor} -k {calendar} egutegia {user}-rekin partekatu du",
+ "{actor} unshared calendar {calendar} from you" : "{actor} zurekin partekatzen zuen {calendar} egutegia partekatzeari utzi dio",
+ "You unshared calendar {calendar} from {user}" : "Partekatzen zenuen {calendar} egutegia {user} -rekin partekatzeari utzi diozu ",
+ "{actor} unshared calendar {calendar} from {user}" : "{actor} {user} erabiltzailearekin partekatzen zuen {calendar} egutegia partekatzeari utzi dio",
+ "{actor} unshared calendar {calendar} from themselves" : "{actor} {calendar} egutegia partekatzeari utzi dio bere buruarekin",
+ "You shared calendar {calendar} with group {group}" : "{calendar} egutegia {group} taldearekin partekatu duz",
+ "{actor} shared calendar {calendar} with group {group}" : "{actor} {group} taldearekin {calendar} egutegia partekatu du",
+ "You unshared calendar {calendar} from group {group}" : "{group} taldearekin {calendar} egutegia partekatzeari utzi dio.",
+ "{actor} unshared calendar {calendar} from group {group}" : "{actor}-rk {group} taldearekin {calendar} egutegia partekatzeari utzi dio.",
+ "{actor} created event {event} in calendar {calendar}" : "{actor} {event} jarduera {calendar} egutegian sortu du.",
+ "You created event {event} in calendar {calendar}" : "{calendar} egutegia {event} jarduera sortu duzu",
+ "{actor} deleted event {event} from calendar {calendar}" : "{actor}-rk {event} jarduera {calendar} egutegitik borratu du",
+ "You deleted event {event} from calendar {calendar}" : "{event} jarduera {calendar} egutegitik borratu duzu",
+ "{actor} updated event {event} in calendar {calendar}" : "{actor}-rek {event} jarduera {calendar} egutegian eguneratu da",
+ "You updated event {event} in calendar {calendar}" : "{event} jarduera {calendar} egutegian eguneratu duzu ",
+ "{actor} created todo {todo} in list {calendar}" : "{actor}-rek {calendar} zerrendan {todo} ekintza sortu du.",
+ "You created todo {todo} in list {calendar}" : "{calendar} zerrendan {todo} ekintza sortu duzu.",
+ "{actor} deleted todo {todo} from list {calendar}" : "{actor}-rek {calendar} zerrendan {todo} zeregina borratu du.",
+ "You deleted todo {todo} from list {calendar}" : " {calendar} zerrendan {todo} zeregina borratu duzu.",
+ "{actor} updated todo {todo} in list {calendar}" : "{actor}-rek {calendar} zerrendan {todo} zeregina eguneratu du.",
+ "You updated todo {todo} in list {calendar}" : "{calendar} zerrendan {todo} zeregina eguneratu duzu.",
+ "{actor} solved todo {todo} in list {calendar}" : "{actor}-rek {calendar} zerrendan {todo} zeregina bukatu du.",
+ "You solved todo {todo} in list {calendar}" : " {calendar} zerrendan {todo} zeregina bukatu duzu.",
+ "{actor} reopened todo {todo} in list {calendar}" : "{actor}-rek {calendar} zerrendan {todo} zeregina birreki du.",
+ "You reopened todo {todo} in list {calendar}" : "{calendar} zerrendan {todo} zeregina birreki duzu. ",
+ "A <strong>calendar</strong> was modified" : "Egutegia aldatu da",
+ "A calendar <strong>event</strong> was modified" : "Egutegiaren zeregin bat aldatu da",
+ "A calendar <strong>todo</strong> was modified" : "Egutegiaren zeregin bat aldatu da",
+ "Contact birthdays" : "Urtebetetze kontaktua",
+ "Invitation canceled" : "Gonbidapena ezeztatua",
+ "Hello %s," : "Kaixo 1%s,",
+ "The meeting »%s« with %s was canceled." : "1%s-rekin duzun » 1%s « bilera ezeztatu da",
+ "Invitation updated" : "Gonbidapena eguneratu da",
+ "%s invited you to »%s«" : "1%s-k »1%s«-ra gonbidatu zaitu",
+ "When:" : "Noiz:",
+ "Where:" : "Non:",
+ "Description:" : "Deskribapena:",
+ "Link:" : "Esteka:",
+ "Contacts" : "Kontaktuak",
+ "Technical details" : "Xehetasun teknikoak",
+ "Remote Address: %s" : "Urruneko helbidea: 1%s",
+ "Request ID: %s" : "Eskatutako ID: 1%s",
+ "CalDAV server" : "CalDAV zerbitzaria",
+ "Send invitations to attendees" : "Gonbidatutakoei gonbidapenak bidali",
+ "Please make sure to properly set up the email settings above." : "Mesedez, eposta ezarpenak ondo zehaztuta daudela ziurta ezazu"
+},
+"nplurals=2; plural=(n != 1);");
diff --git a/apps/dav/l10n/eu.json b/apps/dav/l10n/eu.json
new file mode 100644
index 00000000000..8ab7ee3b892
--- /dev/null
+++ b/apps/dav/l10n/eu.json
@@ -0,0 +1,59 @@
+{ "translations": {
+ "Calendar" : "Egutegia",
+ "Todos" : "Egitekoak",
+ "Personal" : "Pertsonala",
+ "{actor} created calendar {calendar}" : "{actor}-k sortutako egutegia: {calendar}",
+ "You created calendar {calendar}" : "{calendar} egutegia sortu duzu",
+ "{actor} deleted calendar {calendar}" : "{actor}-k {calendar} egutegia borratu du",
+ "You deleted calendar {calendar}" : "{calendar} egutegia borratu duzu",
+ "{actor} updated calendar {calendar}" : "{actor} -k {calendar} egutegia eguneratu du",
+ "You updated calendar {calendar}" : "{calendar} egutegia eguneratu duzu ",
+ "{actor} shared calendar {calendar} with you" : "{actor} -k zurekin {calendar} egutegia partekatu du",
+ "You shared calendar {calendar} with {user}" : "{calendar} egutegia {user} erabiltzailearekin partekatu duzu",
+ "{actor} shared calendar {calendar} with {user}" : "{actor} -k {calendar} egutegia {user}-rekin partekatu du",
+ "{actor} unshared calendar {calendar} from you" : "{actor} zurekin partekatzen zuen {calendar} egutegia partekatzeari utzi dio",
+ "You unshared calendar {calendar} from {user}" : "Partekatzen zenuen {calendar} egutegia {user} -rekin partekatzeari utzi diozu ",
+ "{actor} unshared calendar {calendar} from {user}" : "{actor} {user} erabiltzailearekin partekatzen zuen {calendar} egutegia partekatzeari utzi dio",
+ "{actor} unshared calendar {calendar} from themselves" : "{actor} {calendar} egutegia partekatzeari utzi dio bere buruarekin",
+ "You shared calendar {calendar} with group {group}" : "{calendar} egutegia {group} taldearekin partekatu duz",
+ "{actor} shared calendar {calendar} with group {group}" : "{actor} {group} taldearekin {calendar} egutegia partekatu du",
+ "You unshared calendar {calendar} from group {group}" : "{group} taldearekin {calendar} egutegia partekatzeari utzi dio.",
+ "{actor} unshared calendar {calendar} from group {group}" : "{actor}-rk {group} taldearekin {calendar} egutegia partekatzeari utzi dio.",
+ "{actor} created event {event} in calendar {calendar}" : "{actor} {event} jarduera {calendar} egutegian sortu du.",
+ "You created event {event} in calendar {calendar}" : "{calendar} egutegia {event} jarduera sortu duzu",
+ "{actor} deleted event {event} from calendar {calendar}" : "{actor}-rk {event} jarduera {calendar} egutegitik borratu du",
+ "You deleted event {event} from calendar {calendar}" : "{event} jarduera {calendar} egutegitik borratu duzu",
+ "{actor} updated event {event} in calendar {calendar}" : "{actor}-rek {event} jarduera {calendar} egutegian eguneratu da",
+ "You updated event {event} in calendar {calendar}" : "{event} jarduera {calendar} egutegian eguneratu duzu ",
+ "{actor} created todo {todo} in list {calendar}" : "{actor}-rek {calendar} zerrendan {todo} ekintza sortu du.",
+ "You created todo {todo} in list {calendar}" : "{calendar} zerrendan {todo} ekintza sortu duzu.",
+ "{actor} deleted todo {todo} from list {calendar}" : "{actor}-rek {calendar} zerrendan {todo} zeregina borratu du.",
+ "You deleted todo {todo} from list {calendar}" : " {calendar} zerrendan {todo} zeregina borratu duzu.",
+ "{actor} updated todo {todo} in list {calendar}" : "{actor}-rek {calendar} zerrendan {todo} zeregina eguneratu du.",
+ "You updated todo {todo} in list {calendar}" : "{calendar} zerrendan {todo} zeregina eguneratu duzu.",
+ "{actor} solved todo {todo} in list {calendar}" : "{actor}-rek {calendar} zerrendan {todo} zeregina bukatu du.",
+ "You solved todo {todo} in list {calendar}" : " {calendar} zerrendan {todo} zeregina bukatu duzu.",
+ "{actor} reopened todo {todo} in list {calendar}" : "{actor}-rek {calendar} zerrendan {todo} zeregina birreki du.",
+ "You reopened todo {todo} in list {calendar}" : "{calendar} zerrendan {todo} zeregina birreki duzu. ",
+ "A <strong>calendar</strong> was modified" : "Egutegia aldatu da",
+ "A calendar <strong>event</strong> was modified" : "Egutegiaren zeregin bat aldatu da",
+ "A calendar <strong>todo</strong> was modified" : "Egutegiaren zeregin bat aldatu da",
+ "Contact birthdays" : "Urtebetetze kontaktua",
+ "Invitation canceled" : "Gonbidapena ezeztatua",
+ "Hello %s," : "Kaixo 1%s,",
+ "The meeting »%s« with %s was canceled." : "1%s-rekin duzun » 1%s « bilera ezeztatu da",
+ "Invitation updated" : "Gonbidapena eguneratu da",
+ "%s invited you to »%s«" : "1%s-k »1%s«-ra gonbidatu zaitu",
+ "When:" : "Noiz:",
+ "Where:" : "Non:",
+ "Description:" : "Deskribapena:",
+ "Link:" : "Esteka:",
+ "Contacts" : "Kontaktuak",
+ "Technical details" : "Xehetasun teknikoak",
+ "Remote Address: %s" : "Urruneko helbidea: 1%s",
+ "Request ID: %s" : "Eskatutako ID: 1%s",
+ "CalDAV server" : "CalDAV zerbitzaria",
+ "Send invitations to attendees" : "Gonbidatutakoei gonbidapenak bidali",
+ "Please make sure to properly set up the email settings above." : "Mesedez, eposta ezarpenak ondo zehaztuta daudela ziurta ezazu"
+},"pluralForm" :"nplurals=2; plural=(n != 1);"
+} \ No newline at end of file
diff --git a/apps/files/css/files.scss b/apps/files/css/files.scss
index d1405517f13..1be3c9216f0 100644
--- a/apps/files/css/files.scss
+++ b/apps/files/css/files.scss
@@ -47,14 +47,6 @@
top: 44px;
}
-/* make sure there's enough room for the file actions */
-#body-user #filestable {
- min-width: 688px; /* 768 (mobile break) - 80 (nav width) */
-}
-#body-user #controls {
- min-width: 688px; /* 768 (mobile break) - 80 (nav width) */
-}
-
#filestable tbody tr {
height: 51px;
}
@@ -74,12 +66,16 @@
background-color: rgb(179, 230, 255)!important;
}
-.app-files #app-content.dir-drop, .file-drag #filestable tbody tr, .file-drag #filestable tbody tr:hover{
- background-color: rgba(0, 0, 0, 0)!important;
+.app-files #app-content.dir-drop {
+ background-color: $color-main-background !important;
+}
+
+.file-drag #filestable tbody tr, .file-drag #filestable tbody tr:hover{
+ background-color: transparent !important;
}
.app-files #app-content.dir-drop #filestable tbody tr.dropping-to-dir{
- background-color: rgb(179, 230, 255)!important;
+ background-color: rgb(179, 230, 255) !important;
}
/* icons for sidebar */
@@ -740,9 +736,9 @@ table.dragshadow td.size {
margin-bottom: 2px;
}
-.canDrop,
+.breadcrumb .canDrop > a,
#filestable tbody tr.canDrop {
- background-color: rgba(255, 255, 140, 1);
+ background-color: rgb(179, 230, 255);
}
diff --git a/apps/files/img/add-color.png b/apps/files/img/add-color.png
index 2211eb6e0bc..f2819c3aca6 100644
--- a/apps/files/img/add-color.png
+++ b/apps/files/img/add-color.png
Binary files differ
diff --git a/apps/files/img/add-color.svg b/apps/files/img/add-color.svg
index acf5543c43f..cb4596ac1e5 100644
--- a/apps/files/img/add-color.svg
+++ b/apps/files/img/add-color.svg
@@ -1,6 +1 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1">
- <g transform="matrix(-.70711 -.70711 .70711 -.70711 -724.85 753.16)" fill="#00d400">
- <path d="m3.7547 1041.6 1.4142-1.4142 3.5355 3.5355 3.5355-3.5355 1.4142 1.4142-3.5355 3.5355 3.5355 3.5356-1.4142 1.4142-3.5355-3.5356-3.5164 3.5547-1.4333-1.4333 3.5355-3.5356z" fill="#00d400"/>
- </g>
-</svg>
+<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" viewbox="0 0 16 16"><path fill="#00d400" d="M9.02 13.98h-2v-5h-5v-2h5v-5h2v5l5-.028V8.98h-5z"/></svg>
diff --git a/apps/files/img/delete.svg b/apps/files/img/delete.svg
index c20929aaa18..53f0b020eb9 100644
--- a/apps/files/img/delete.svg
+++ b/apps/files/img/delete.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16"><path d="M6.5 1L6 2H3c-.554 0-1 .446-1 1v1h12V3c0-.554-.446-1-1-1h-3l-.5-1zM3 5l.875 9c.06.55.573 1 1.125 1h6c.552 0 1.064-.45 1.125-1L13 5z" fill-rule="evenodd"/></svg> \ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewbox="0 0 16 16" width="16" height="16"><path d="M6.5 1L6 2H3c-.554 0-1 .446-1 1v1h12V3c0-.554-.446-1-1-1h-3l-.5-1zM3 5l.875 9c.06.55.573 1 1.125 1h6c.552 0 1.064-.45 1.125-1L13 5z"/></svg>
diff --git a/apps/files/img/share.svg b/apps/files/img/share.svg
index c0ad9522369..014392d5a57 100644
--- a/apps/files/img/share.svg
+++ b/apps/files/img/share.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16"><path d="M12.228 1a2.457 2.457 0 0 0-2.46 2.454c0 .075.01.15.016.224L5.05 6.092a2.445 2.445 0 0 0-1.596-.586A2.453 2.453 0 0 0 1 7.96a2.453 2.453 0 0 0 2.454 2.455 2.45 2.45 0 0 0 1.46-.477l4.865 2.474c-.004.044-.01.09-.01.134a2.457 2.457 0 1 0 .804-1.818l-4.696-2.4c.02-.123.035-.25.035-.378 0-.072-.01-.144-.015-.214l4.74-2.414A2.457 2.457 0 1 0 12.228.99z"/></svg> \ No newline at end of file
+<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" version="1.1" viewBox="0 0 16 16"><circle cx="3.5" cy="8" r="2.5"/><circle cy="12.5" cx="12.5" r="2.5"/><circle cx="12.5" cy="3.5" r="2.5"/><path d="m3.5 8 9 4.5m-9-4.5 9-4.5" stroke="#000" stroke-width="2" fill="none"/></svg>
diff --git a/apps/files/js/breadcrumb.js b/apps/files/js/breadcrumb.js
index 2a4c2bc8a52..35aeb8d357d 100644
--- a/apps/files/js/breadcrumb.js
+++ b/apps/files/js/breadcrumb.js
@@ -33,6 +33,9 @@
*/
var BreadCrumb = function(options){
this.$el = $('<div class="breadcrumb"></div>');
+ this.$menu = $('<div class="popovermenu menu-center"><ul></ul></div>');
+
+ this.crumbSelector = '.crumb:not(.hidden):not(.crumbhome):not(.crumbmenu)';
options = options || {};
if (options.onClick) {
this.onClick = options.onClick;
@@ -47,6 +50,7 @@
}
this._detailViews = [];
};
+
/**
* @memberof OCA.Files
*/
@@ -110,19 +114,32 @@
* Renders the breadcrumb elements
*/
render: function() {
+ // Menu is destroyed on every change, we need to init it
+ OC.unregisterMenu($('.crumbmenu'), $('.crumbmenu > .popovermenu'));
+
var parts = this._makeCrumbs(this.dir || '/');
var $crumb;
+ var $menuItem;
this.$el.empty();
this.breadcrumbs = [];
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
var $image;
- var $link = $('<a></a>').attr('href', this.getCrumbUrl(part, i));
- $link.text(part.name);
+ var $link = $('<a></a>');
$crumb = $('<div class="crumb svg"></div>');
+ if(part.dir) {
+ $link.attr('href', this.getCrumbUrl(part, i));
+ }
+ if(part.name) {
+ $link.text(part.name);
+ }
+ $link.addClass(part.linkclass);
$crumb.append($link);
- $crumb.attr('data-dir', part.dir);
+ $crumb.data('dir', part.dir);
+ // Ignore menu button
+ $crumb.data('crumb-id', i - 1);
+ $crumb.addClass(part.class);
if (part.img) {
$image = $('<img class="svg"></img>');
@@ -132,12 +149,27 @@
}
this.breadcrumbs.push($crumb);
this.$el.append($crumb);
- if (this.onClick) {
- $crumb.on('click', this.onClick);
+ // Only add feedback if not menu
+ if (this.onClick && i !== 0) {
+ $link.on('click', this.onClick);
}
}
- $crumb.addClass('last');
+ // Menu creation
+ this._createMenu();
+ for (var j = 0; j < parts.length; j++) {
+ var menuPart = parts[j];
+ if(menuPart.dir) {
+ $menuItem = $('<li class="crumblist"><a><span class="icon-folder"></span><span></span></a></li>');
+ $menuItem.data('dir', menuPart.dir);
+ $menuItem.find('a').attr('href', this.getCrumbUrl(part, j));
+ $menuItem.find('span:eq(1)').text(menuPart.name);
+ this.$menu.children('ul').append($menuItem);
+ if (this.onClick) {
+ $menuItem.on('click', this.onClick);
+ }
+ }
+ }
_.each(this._detailViews, function(view) {
view.render({
dirInfo: this.dirInfo
@@ -152,16 +184,20 @@
// setup drag and drop
if (this.onDrop) {
- this.$el.find('.crumb:not(.last)').droppable({
+ this.$el.find('.crumb:not(:last-child):not(.crumbmenu), .crumblist:not(:last-child)').droppable({
drop: this.onDrop,
over: this.onOver,
out: this.onOut,
tolerance: 'pointer',
- hoverClass: 'canDrop'
+ hoverClass: 'canDrop',
+ greedy: true
});
}
- this._updateTotalWidth();
+ // Menu is destroyed on every change, we need to init it
+ OC.registerMenu($('.crumbmenu'), $('.crumbmenu > .popovermenu'));
+
+ this._resize();
},
/**
@@ -179,12 +215,17 @@
if (dir === '') {
parts = [];
}
+ // menu part
+ crumbs.push({
+ class: 'crumbmenu hidden',
+ linkclass: 'icon-more'
+ });
// root part
crumbs.push({
+ name: t('core', 'Home'),
dir: '/',
- name: '',
- alt: t('files', 'Home'),
- img: OC.imagePath('core', 'places/home.svg')
+ class: 'crumbhome',
+ linkclass: 'icon-home'
});
for (var i = 0; i < parts.length; i++) {
var part = parts[i];
@@ -198,22 +239,9 @@
},
/**
- * Calculate the total breadcrumb width when
- * all crumbs are expanded
- */
- _updateTotalWidth: function () {
- this.totalWidth = 0;
- for (var i = 0; i < this.breadcrumbs.length; i++ ) {
- var $crumb = $(this.breadcrumbs[i]);
- $crumb.data('real-width', $crumb.width());
- this.totalWidth += $crumb.width();
- }
- this._resize();
- },
-
- /**
* Show/hide breadcrumbs to fit the given width
- *
+ * Mostly used by tests
+ *
* @param {int} availableWidth available width
*/
setMaxWidth: function (availableWidth) {
@@ -223,74 +251,107 @@
}
},
- _resize: function() {
- var i, $crumb, $ellipsisCrumb;
-
- if (!this.availableWidth) {
- this.availableWidth = this.$el.width();
+ /**
+ * Calculate real width based on individual crumbs
+ * More accurate and works with tests
+ *
+ * @param {boolean} ignoreHidden ignore hidden crumbs
+ */
+ getTotalWidth: function(ignoreHidden) {
+ var totalWidth = 0;
+ for (var i = 0; i < this.breadcrumbs.length; i++ ) {
+ var $crumb = $(this.breadcrumbs[i]);
+ if(!$crumb.hasClass('hidden') || ignoreHidden === true) {
+ totalWidth += $crumb.outerWidth();
+ }
}
+ return totalWidth;
+ },
- if (this.breadcrumbs.length <= 1) {
- return;
+ /**
+ * Hide the middle crumb
+ */
+ _hideCrumb: function() {
+ var length = this.$el.find(this.crumbSelector).length;
+ // Get the middle one floored down
+ var elmt = Math.floor(length / 2 - 0.5);
+ this.$el.find(this.crumbSelector+':eq('+elmt+')').addClass('hidden');
+ },
+
+ /**
+ * Get the crumb to show
+ */
+ _getCrumbElement: function() {
+ var hidden = this.$el.find('.crumb.hidden').length;
+ var shown = this.$el.find(this.crumbSelector).length;
+ // Get the outer one with priority to the highest
+ var elmt = (1 - shown % 2) * (hidden - 1);
+ return this.$el.find('.crumb.hidden:eq('+elmt+')');
+ },
+
+ /**
+ * Show the middle crumb
+ */
+ _showCrumb: function() {
+ if(this.$el.find('.crumb.hidden').length === 1) {
+ this.$el.find('.crumb.hidden').removeClass('hidden');
}
+ this._getCrumbElement().removeClass('hidden');
+ },
+
+ /**
+ * Create and append the popovermenu
+ */
+ _createMenu: function() {
+ this.$el.find('.crumbmenu').append(this.$menu);
+ this.$menu.children('ul').empty();
+ },
+
+ /**
+ * Update the popovermenu
+ */
+ _updateMenu: function() {
+ var menuItems = this.$el.find('.crumb.hidden');
+ // Hide the crumb menu if no elements
+ this.$el.find('.crumbmenu').toggleClass('hidden', menuItems.length === 0);
- // reset crumbs
- this.$el.find('.crumb.ellipsized').remove();
+ this.$menu.find('li').addClass('in-breadcrumb');
+ for (var i = 0; i < menuItems.length; i++) {
+ var crumbId = $(menuItems[i]).data('crumb-id');
+ this.$menu.find('li:eq('+crumbId+')').removeClass('in-breadcrumb');
+ }
+ },
- // unhide all
- this.$el.find('.crumb.hidden').removeClass('hidden');
+ _resize: function() {
- if (this.totalWidth <= this.availableWidth) {
- // no need to compute breadcrumbs, there is enough space
+ if (this.breadcrumbs.length <= 2) {
+ // home & menu
return;
}
- // running width, considering the hidden crumbs
- var currentTotalWidth = $(this.breadcrumbs[0]).data('real-width');
- var firstHidden = true;
-
- // insert ellipsis after root part (root part is always visible)
- $ellipsisCrumb = $('<div class="crumb ellipsized svg"><span class="ellipsis">...</span></div>');
- $(this.breadcrumbs[0]).after($ellipsisCrumb);
- currentTotalWidth += $ellipsisCrumb.width();
-
- i = this.breadcrumbs.length - 1;
-
- // find the first section that would cause the overflow
- // then hide everything in front of that
- //
- // this ensures that the last crumb section stays visible
- // for most of the cases and is always the last one to be
- // hidden when the screen becomes very narrow
- while (i > 0) {
- $crumb = $(this.breadcrumbs[i]);
- // if the current breadcrumb would cause overflow
- if (!firstHidden || currentTotalWidth + $crumb.data('real-width') > this.availableWidth) {
- // hide it
- $crumb.addClass('hidden');
- if (firstHidden) {
- // set the path of this one as title for the ellipsis
- this.$el.find('.crumb.ellipsized')
- .attr('title', $crumb.attr('data-dir'))
- .tooltip();
- this.$el.find('.ellipsis')
- .wrap('<a class="ellipsislink" href="' + encodeURI(OC.generateUrl('apps/files/?dir=' + $crumb.attr('data-dir'))) + '"></a>');
- }
- // and all the previous ones (going backwards)
- firstHidden = false;
- } else {
- // add to total width
- currentTotalWidth += $crumb.data('real-width');
- }
- i--;
+ // Used for testing since this.$el.parent fails
+ if (!this.availableWidth) {
+ this.usedWidth = this.$el.parent().width() - (this.$el.parent().find('.button').length + 1) * 44;
+ } else {
+ this.usedWidth = this.availableWidth;
}
- if (!OC.Util.hasSVGSupport()) {
- OC.Util.replaceSVG(this.$el);
+ // If container is smaller than content
+ // AND if there are crumbs left to hide
+ while (this.getTotalWidth() > this.usedWidth
+ && this.$el.find(this.crumbSelector).length > 0) {
+ this._hideCrumb();
}
+ // If container is bigger than content + element to be shown
+ // AND if there is at least one hidden crumb
+ while (this.$el.find('.crumb.hidden').length > 0
+ && this.getTotalWidth() + this._getCrumbElement().width() < this.usedWidth) {
+ this._showCrumb();
+ }
+
+ this._updateMenu();
}
};
OCA.Files.BreadCrumb = BreadCrumb;
})();
-
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index af5e9c013f0..03e9c138efb 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -322,7 +322,7 @@
this.$el.find('thead th .columntitle').click(_.bind(this._onClickHeader, this));
- this._onResize = _.debounce(_.bind(this._onResize, this), 100);
+ this._onResize = _.debounce(_.bind(this._onResize, this), 250);
$('#app-content').on('appresized', this._onResize);
$(window).resize(this._onResize);
@@ -556,7 +556,7 @@
// subtract app navigation toggle when visible
containerWidth -= $('#app-navigation-toggle').width();
- this.breadcrumb.setMaxWidth(containerWidth - actionsWidth - 10);
+ this.breadcrumb._resize();
this.$table.find('>thead').width($('#app-content').width() - OC.Util.getScrollBarWidth());
},
@@ -837,7 +837,8 @@
* Event handler when clicking on a bread crumb
*/
_onClickBreadCrumb: function(e) {
- var $el = $(e.target).closest('.crumb'),
+ // Select a crumb or a crumb in the menu
+ var $el = $(e.target).closest('.crumb, .crumblist'),
$targetDir = $el.data('dir');
if ($targetDir !== undefined && e.which === 1) {
@@ -863,8 +864,8 @@
_onDropOnBreadCrumb: function( event, ui ) {
var self = this;
var $target = $(event.target);
- if (!$target.is('.crumb')) {
- $target = $target.closest('.crumb');
+ if (!$target.is('.crumb, .crumblist')) {
+ $target = $target.closest('.crumb, .crumblist');
}
var targetPath = $(event.target).data('dir');
var dir = this.getCurrentDirectory();
@@ -1284,7 +1285,7 @@
fileData.extraData = fileData.extraData.substr(1);
}
nameSpan.addClass('extra-data').attr('title', fileData.extraData);
- nameSpan.tooltip({placement: 'right'});
+ nameSpan.tooltip({placement: 'top'});
}
// dirs can show the number of uploaded files
if (mime === 'httpd/unix-directory') {
@@ -1713,7 +1714,7 @@
if (status === 500) {
// Go home
this.changeDirectory('/');
- OC.Notification.show(t('files', 'This directory is unavailable, please check the logs or contact the administrator'),
+ OC.Notification.show(t('files', 'This directory is unavailable, please check the logs or contact the administrator'),
{type: 'error'}
);
return false;
@@ -1724,7 +1725,7 @@
if (this.getCurrentDirectory() !== '/') {
this.changeDirectory('/');
// TODO: read error message from exception
- OC.Notification.show(t('files', 'Storage is temporarily not available'),
+ OC.Notification.show(t('files', 'Storage is temporarily not available'),
{type: 'error'}
);
}
@@ -2040,11 +2041,11 @@
.fail(function(status) {
if (status === 412) {
// TODO: some day here we should invoke the conflict dialog
- OC.Notification.show(t('files', 'Could not move "{file}", target exists',
+ OC.Notification.show(t('files', 'Could not move "{file}", target exists',
{file: fileName}), {type: 'error'}
);
} else {
- OC.Notification.show(t('files', 'Could not move "{file}"',
+ OC.Notification.show(t('files', 'Could not move "{file}"',
{file: fileName}), {type: 'error'}
);
}
@@ -2271,7 +2272,7 @@
// TODO: 409 means current folder does not exist, redirect ?
if (status === 404) {
// source not found, so remove it from the list
- OC.Notification.show(t('files', 'Could not rename "{fileName}", it does not exist any more',
+ OC.Notification.show(t('files', 'Could not rename "{fileName}", it does not exist any more',
{fileName: oldName}), {timeout: 7, type: 'error'}
);
@@ -2291,7 +2292,7 @@
);
} else {
// restore the item to its previous state
- OC.Notification.show(t('files', 'Could not rename "{fileName}"',
+ OC.Notification.show(t('files', 'Could not rename "{fileName}"',
{fileName: oldName}), {type: 'error'}
);
}
@@ -2376,18 +2377,18 @@
self.addAndFetchFileInfo(targetPath, '', {scrollTo: true}).then(function(status, data) {
deferred.resolve(status, data);
}, function() {
- OC.Notification.show(t('files', 'Could not create file "{file}"',
+ OC.Notification.show(t('files', 'Could not create file "{file}"',
{file: name}), {type: 'error'}
);
});
})
.fail(function(status) {
if (status === 412) {
- OC.Notification.show(t('files', 'Could not create file "{file}" because it already exists',
+ OC.Notification.show(t('files', 'Could not create file "{file}" because it already exists',
{file: name}), {type: 'error'}
);
} else {
- OC.Notification.show(t('files', 'Could not create file "{file}"',
+ OC.Notification.show(t('files', 'Could not create file "{file}"',
{file: name}), {type: 'error'}
);
}
@@ -2426,7 +2427,7 @@
self.addAndFetchFileInfo(targetPath, '', {scrollTo:true}).then(function(status, data) {
deferred.resolve(status, data);
}, function() {
- OC.Notification.show(t('files', 'Could not create folder "{dir}"',
+ OC.Notification.show(t('files', 'Could not create folder "{dir}"',
{dir: name}), {type: 'error'}
);
});
@@ -2437,20 +2438,20 @@
// add it to the list, for completeness
self.addAndFetchFileInfo(targetPath, '', {scrollTo:true})
.done(function(status, data) {
- OC.Notification.show(t('files', 'Could not create folder "{dir}" because it already exists',
+ OC.Notification.show(t('files', 'Could not create folder "{dir}" because it already exists',
{dir: name}), {type: 'error'}
);
// still consider a failure
deferred.reject(createStatus, data);
})
.fail(function() {
- OC.Notification.show(t('files', 'Could not create folder "{dir}"',
+ OC.Notification.show(t('files', 'Could not create folder "{dir}"',
{dir: name}), {type: 'error'}
);
deferred.reject(status);
});
} else {
- OC.Notification.show(t('files', 'Could not create folder "{dir}"',
+ OC.Notification.show(t('files', 'Could not create folder "{dir}"',
{dir: name}), {type: 'error'}
);
deferred.reject(createStatus);
@@ -2507,7 +2508,7 @@
deferred.resolve(status, data);
})
.fail(function(status) {
- OC.Notification.show(t('files', 'Could not create file "{file}"',
+ OC.Notification.show(t('files', 'Could not create file "{file}"',
{file: name}), {type: 'error'}
);
deferred.reject(status);
@@ -2616,7 +2617,7 @@
removeFromList(file);
} else {
// only reset the spinner for that one file
- OC.Notification.show(t('files', 'Error deleting file "{fileName}".',
+ OC.Notification.show(t('files', 'Error deleting file "{fileName}".',
{fileName: file}), {type: 'error'}
);
var deleteAction = self.findFileEl(file).find('.action.delete');
diff --git a/apps/files/js/files.js b/apps/files/js/files.js
index e34d7fe2550..017bf7ecf41 100644
--- a/apps/files/js/files.js
+++ b/apps/files/js/files.js
@@ -117,32 +117,32 @@
ownerDisplayName = $('#ownerDisplayName').val();
if (usedSpacePercent > 98) {
if (owner !== oc_current_user) {
- OC.Notification.show(t('files', 'Storage of {owner} is full, files can not be updated or synced anymore!',
+ OC.Notification.show(t('files', 'Storage of {owner} is full, files can not be updated or synced anymore!',
{owner: ownerDisplayName}), {type: 'error'}
);
return;
}
- OC.Notification.show(t('files',
- 'Your storage is full, files can not be updated or synced anymore!'),
+ OC.Notification.show(t('files',
+ 'Your storage is full, files can not be updated or synced anymore!'),
{type : 'error'}
);
return;
}
if (usedSpacePercent > 90) {
if (owner !== oc_current_user) {
- OC.Notification.show(t('files', 'Storage of {owner} is almost full ({usedSpacePercent}%)',
+ OC.Notification.show(t('files', 'Storage of {owner} is almost full ({usedSpacePercent}%)',
{
- usedSpacePercent: usedSpacePercent,
+ usedSpacePercent: usedSpacePercent,
owner: ownerDisplayName
}),
- {
+ {
type: 'error'
}
);
return;
}
OC.Notification.show(t('files', 'Your storage is almost full ({usedSpacePercent}%)',
- {usedSpacePercent: usedSpacePercent}),
+ {usedSpacePercent: usedSpacePercent}),
{type : 'error'}
);
}
@@ -396,6 +396,8 @@ var dragOptions={
}
$selectedFiles.closest('tr').addClass('animate-opacity dragging');
$selectedFiles.closest('tr').filter('.ui-droppable').droppable( 'disable' );
+ // Show breadcrumbs menu
+ $('.crumbmenu').addClass('canDropChildren');
},
stop: function(event, ui) {
@@ -411,6 +413,8 @@ var dragOptions={
setTimeout(function() {
$tr.removeClass('animate-opacity');
}, 300);
+ // Hide breadcrumbs menu
+ $('.crumbmenu').removeClass('canDropChildren');
},
drag: function(event, ui) {
var scrollingArea = FileList.$container;
diff --git a/apps/files/l10n/da.js b/apps/files/l10n/da.js
index 8c82974369f..0c8fea1c3ff 100644
--- a/apps/files/l10n/da.js
+++ b/apps/files/l10n/da.js
@@ -19,6 +19,8 @@ OC.L10N.register(
"Uploading …" : "Uploader ...",
"…" : "...",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} af {totalSize} ({bitrate})",
+ "Target folder does not exist any more" : "Destinations mappen findes ikke længere",
+ "Error when assembling chunks, status code {status}" : "Fejl ved montering af klumper, statuskode {status}",
"Actions" : "Handlinger",
"Download" : "Hent",
"Rename" : "Omdøb",
@@ -125,6 +127,7 @@ OC.L10N.register(
"Settings" : "Indstillinger",
"Show hidden files" : "Vis skjulte filer",
"WebDAV" : "WebDAV",
+ "Use this address to <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">access your Files via WebDAV</a>" : "Brug denne adresse til at <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">få adgang til dine filer via WebDAV</a>",
"Cancel upload" : "Annuller upload ",
"No files in here" : "Her er ingen filer",
"Upload some content or sync with your devices!" : "Overfør indhold eller synkronisér med dine enheder!",
diff --git a/apps/files/l10n/da.json b/apps/files/l10n/da.json
index 4d83d9fa6c0..ae52158a78d 100644
--- a/apps/files/l10n/da.json
+++ b/apps/files/l10n/da.json
@@ -17,6 +17,8 @@
"Uploading …" : "Uploader ...",
"…" : "...",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} af {totalSize} ({bitrate})",
+ "Target folder does not exist any more" : "Destinations mappen findes ikke længere",
+ "Error when assembling chunks, status code {status}" : "Fejl ved montering af klumper, statuskode {status}",
"Actions" : "Handlinger",
"Download" : "Hent",
"Rename" : "Omdøb",
@@ -123,6 +125,7 @@
"Settings" : "Indstillinger",
"Show hidden files" : "Vis skjulte filer",
"WebDAV" : "WebDAV",
+ "Use this address to <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">access your Files via WebDAV</a>" : "Brug denne adresse til at <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">få adgang til dine filer via WebDAV</a>",
"Cancel upload" : "Annuller upload ",
"No files in here" : "Her er ingen filer",
"Upload some content or sync with your devices!" : "Overfør indhold eller synkronisér med dine enheder!",
diff --git a/apps/files/l10n/el.js b/apps/files/l10n/el.js
index 064bdd838e2..b5b0738d85b 100644
--- a/apps/files/l10n/el.js
+++ b/apps/files/l10n/el.js
@@ -16,10 +16,13 @@ OC.L10N.register(
"Not enough free space, you are uploading {size1} but only {size2} is left" : "Δεν υπάρχει αρκετός ελεύθερος χώρος, μεταφορτώνετε μέγεθος {size1} αλλά υπάρχει χώρος μόνο {size2}",
"Target folder \"{dir}\" does not exist any more" : "Φάκελος προορισμού \"{dir}\" δεν υπάρχει πια",
"Not enough free space" : "Δεν υπάρχει αρκετός ελεύθερος χώρος.",
+ "Uploading …" : "Γίνεται μεταφόρτωση ...",
+ "…" : "…",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} από {totalSize} ({bitrate})",
"Actions" : "Ενέργειες",
"Download" : "Λήψη",
"Rename" : "Μετονομασία",
+ "Move or copy" : "Μετακίνηση ή αντιγραφή",
"Target folder" : "Φάκελος προορισμού",
"Delete" : "Διαγραφή",
"Disconnect storage" : "Αποσυνδεδεμένος αποθηκευτικός χώρος",
@@ -70,6 +73,8 @@ OC.L10N.register(
"Favorite" : "Αγαπημένο",
"New folder" : "Νέος φάκελος",
"Upload file" : "Αποστολή αρχείου",
+ "Remove from favorites" : "Αφαίρεση από τα αγαπημένα",
+ "Add to favorites" : "Προσθήκη στα αγαπημένα",
"An error occurred while trying to update the tags" : "Ένα σφάλμα προέκυψε κατά τη διάρκεια ενημέρωσης των ετικετών",
"Added to favorites" : "Προσθήκη στα αγαπημένα",
"Removed from favorites" : "Αφαίρεση από τα αγαπημένα",
@@ -115,6 +120,7 @@ OC.L10N.register(
"Settings" : "Ρυθμίσεις",
"Show hidden files" : "Εμφάνιση κρυφών αρχείων",
"WebDAV" : "WebDAV",
+ "Cancel upload" : "Ακύρωση μεταφόρτωσης",
"No files in here" : "Δεν υπάρχουν αρχεία",
"Upload some content or sync with your devices!" : "Μεταφόρτωση περιεχομένου ή συγχρονισμός με τις συσκευές σας!",
"No entries found in this folder" : "Δεν βρέθηκαν καταχωρήσεις σε αυτόν το φάκελο",
diff --git a/apps/files/l10n/el.json b/apps/files/l10n/el.json
index 588c0169920..59acab268be 100644
--- a/apps/files/l10n/el.json
+++ b/apps/files/l10n/el.json
@@ -14,10 +14,13 @@
"Not enough free space, you are uploading {size1} but only {size2} is left" : "Δεν υπάρχει αρκετός ελεύθερος χώρος, μεταφορτώνετε μέγεθος {size1} αλλά υπάρχει χώρος μόνο {size2}",
"Target folder \"{dir}\" does not exist any more" : "Φάκελος προορισμού \"{dir}\" δεν υπάρχει πια",
"Not enough free space" : "Δεν υπάρχει αρκετός ελεύθερος χώρος.",
+ "Uploading …" : "Γίνεται μεταφόρτωση ...",
+ "…" : "…",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} από {totalSize} ({bitrate})",
"Actions" : "Ενέργειες",
"Download" : "Λήψη",
"Rename" : "Μετονομασία",
+ "Move or copy" : "Μετακίνηση ή αντιγραφή",
"Target folder" : "Φάκελος προορισμού",
"Delete" : "Διαγραφή",
"Disconnect storage" : "Αποσυνδεδεμένος αποθηκευτικός χώρος",
@@ -68,6 +71,8 @@
"Favorite" : "Αγαπημένο",
"New folder" : "Νέος φάκελος",
"Upload file" : "Αποστολή αρχείου",
+ "Remove from favorites" : "Αφαίρεση από τα αγαπημένα",
+ "Add to favorites" : "Προσθήκη στα αγαπημένα",
"An error occurred while trying to update the tags" : "Ένα σφάλμα προέκυψε κατά τη διάρκεια ενημέρωσης των ετικετών",
"Added to favorites" : "Προσθήκη στα αγαπημένα",
"Removed from favorites" : "Αφαίρεση από τα αγαπημένα",
@@ -113,6 +118,7 @@
"Settings" : "Ρυθμίσεις",
"Show hidden files" : "Εμφάνιση κρυφών αρχείων",
"WebDAV" : "WebDAV",
+ "Cancel upload" : "Ακύρωση μεταφόρτωσης",
"No files in here" : "Δεν υπάρχουν αρχεία",
"Upload some content or sync with your devices!" : "Μεταφόρτωση περιεχομένου ή συγχρονισμός με τις συσκευές σας!",
"No entries found in this folder" : "Δεν βρέθηκαν καταχωρήσεις σε αυτόν το φάκελο",
diff --git a/apps/files/l10n/es.js b/apps/files/l10n/es.js
index 4f01be175f7..a4666bd7bdf 100644
--- a/apps/files/l10n/es.js
+++ b/apps/files/l10n/es.js
@@ -19,6 +19,8 @@ OC.L10N.register(
"Uploading …" : "Subiendo...",
"…" : "...",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} de {totalSize} ({bitrate})",
+ "Target folder does not exist any more" : "La carpeta destino yano existe",
+ "Error when assembling chunks, status code {status}" : "Error al reunir las partes, código de estado {status}",
"Actions" : "Acciones",
"Download" : "Descargar",
"Rename" : "Renombrar",
diff --git a/apps/files/l10n/es.json b/apps/files/l10n/es.json
index 2b3701aba18..44db92002f2 100644
--- a/apps/files/l10n/es.json
+++ b/apps/files/l10n/es.json
@@ -17,6 +17,8 @@
"Uploading …" : "Subiendo...",
"…" : "...",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} de {totalSize} ({bitrate})",
+ "Target folder does not exist any more" : "La carpeta destino yano existe",
+ "Error when assembling chunks, status code {status}" : "Error al reunir las partes, código de estado {status}",
"Actions" : "Acciones",
"Download" : "Descargar",
"Rename" : "Renombrar",
diff --git a/apps/files/l10n/es_CL.js b/apps/files/l10n/es_CL.js
index 831187b5e11..793abaf101b 100644
--- a/apps/files/l10n/es_CL.js
+++ b/apps/files/l10n/es_CL.js
@@ -19,6 +19,8 @@ OC.L10N.register(
"Uploading …" : "Cargando...",
"…" : "...",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} de {totalSize} ({bitrate})",
+ "Target folder does not exist any more" : "La carpeta destino ya no existe",
+ "Error when assembling chunks, status code {status}" : "Se presentó un error al ensamblar los bloques, código de estatus {status}",
"Actions" : "Acciones",
"Download" : "Descargar",
"Rename" : "Renombrar",
@@ -125,6 +127,7 @@ OC.L10N.register(
"Settings" : "Configuraciones ",
"Show hidden files" : "Mostrar archivos ocultos",
"WebDAV" : "WebDAV",
+ "Use this address to <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">access your Files via WebDAV</a>" : "Usa esta dirección para <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">acceder a tus Archivos vía WebDAV</a>",
"Cancel upload" : "Cancelar carga",
"No files in here" : "No hay archivos aquí",
"Upload some content or sync with your devices!" : "¡Carga algún contenido o sincroniza con tus dispositivos!",
diff --git a/apps/files/l10n/es_CL.json b/apps/files/l10n/es_CL.json
index 374239112ca..4083caedd5e 100644
--- a/apps/files/l10n/es_CL.json
+++ b/apps/files/l10n/es_CL.json
@@ -17,6 +17,8 @@
"Uploading …" : "Cargando...",
"…" : "...",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} de {totalSize} ({bitrate})",
+ "Target folder does not exist any more" : "La carpeta destino ya no existe",
+ "Error when assembling chunks, status code {status}" : "Se presentó un error al ensamblar los bloques, código de estatus {status}",
"Actions" : "Acciones",
"Download" : "Descargar",
"Rename" : "Renombrar",
@@ -123,6 +125,7 @@
"Settings" : "Configuraciones ",
"Show hidden files" : "Mostrar archivos ocultos",
"WebDAV" : "WebDAV",
+ "Use this address to <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">access your Files via WebDAV</a>" : "Usa esta dirección para <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">acceder a tus Archivos vía WebDAV</a>",
"Cancel upload" : "Cancelar carga",
"No files in here" : "No hay archivos aquí",
"Upload some content or sync with your devices!" : "¡Carga algún contenido o sincroniza con tus dispositivos!",
diff --git a/apps/files/l10n/es_MX.js b/apps/files/l10n/es_MX.js
index c4a03ff1225..793abaf101b 100644
--- a/apps/files/l10n/es_MX.js
+++ b/apps/files/l10n/es_MX.js
@@ -19,6 +19,8 @@ OC.L10N.register(
"Uploading …" : "Cargando...",
"…" : "...",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} de {totalSize} ({bitrate})",
+ "Target folder does not exist any more" : "La carpeta destino ya no existe",
+ "Error when assembling chunks, status code {status}" : "Se presentó un error al ensamblar los bloques, código de estatus {status}",
"Actions" : "Acciones",
"Download" : "Descargar",
"Rename" : "Renombrar",
diff --git a/apps/files/l10n/es_MX.json b/apps/files/l10n/es_MX.json
index 2adfe559742..4083caedd5e 100644
--- a/apps/files/l10n/es_MX.json
+++ b/apps/files/l10n/es_MX.json
@@ -17,6 +17,8 @@
"Uploading …" : "Cargando...",
"…" : "...",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} de {totalSize} ({bitrate})",
+ "Target folder does not exist any more" : "La carpeta destino ya no existe",
+ "Error when assembling chunks, status code {status}" : "Se presentó un error al ensamblar los bloques, código de estatus {status}",
"Actions" : "Acciones",
"Download" : "Descargar",
"Rename" : "Renombrar",
diff --git a/apps/files/l10n/fr.js b/apps/files/l10n/fr.js
index 68540aac8d8..c17791b5cbd 100644
--- a/apps/files/l10n/fr.js
+++ b/apps/files/l10n/fr.js
@@ -20,6 +20,7 @@ OC.L10N.register(
"…" : "…",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} sur {totalSize} ({bitrate})",
"Target folder does not exist any more" : "Le dossier cible n'existe plus",
+ "Error when assembling chunks, status code {status}" : "Erreur lors de l'assemblage des blocs, code d'état {status}",
"Actions" : "Actions",
"Download" : "Télécharger",
"Rename" : "Renommer",
diff --git a/apps/files/l10n/fr.json b/apps/files/l10n/fr.json
index 7f675056eb4..77256638126 100644
--- a/apps/files/l10n/fr.json
+++ b/apps/files/l10n/fr.json
@@ -18,6 +18,7 @@
"…" : "…",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} sur {totalSize} ({bitrate})",
"Target folder does not exist any more" : "Le dossier cible n'existe plus",
+ "Error when assembling chunks, status code {status}" : "Erreur lors de l'assemblage des blocs, code d'état {status}",
"Actions" : "Actions",
"Download" : "Télécharger",
"Rename" : "Renommer",
diff --git a/apps/files/l10n/nl.js b/apps/files/l10n/nl.js
index c009bb7496f..fd30a95fb8e 100644
--- a/apps/files/l10n/nl.js
+++ b/apps/files/l10n/nl.js
@@ -19,6 +19,8 @@ OC.L10N.register(
"Uploading …" : "Uploaden …",
"…" : "...",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} van {totalSize} ({bitrate})",
+ "Target folder does not exist any more" : "Doelmap bestaat niet meer",
+ "Error when assembling chunks, status code {status}" : "Fout tijdens samenvoegen van brokken, status code {status}",
"Actions" : "Acties",
"Download" : "Downloaden",
"Rename" : "Naam wijzigen",
@@ -125,6 +127,7 @@ OC.L10N.register(
"Settings" : "Instellingen",
"Show hidden files" : "Verborgen bestanden tonen",
"WebDAV" : "WebDAV",
+ "Use this address to <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">access your Files via WebDAV</a>" : "Gebruik deze link <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">om je bestanden te benaderen via WebDAV</a>",
"Cancel upload" : "Stop upload",
"No files in here" : "Hier geen bestanden",
"Upload some content or sync with your devices!" : "Upload je inhoud of synchroniseer met je apparaten!",
diff --git a/apps/files/l10n/nl.json b/apps/files/l10n/nl.json
index 9a526124372..a74f3f329e4 100644
--- a/apps/files/l10n/nl.json
+++ b/apps/files/l10n/nl.json
@@ -17,6 +17,8 @@
"Uploading …" : "Uploaden …",
"…" : "...",
"{loadedSize} of {totalSize} ({bitrate})" : "{loadedSize} van {totalSize} ({bitrate})",
+ "Target folder does not exist any more" : "Doelmap bestaat niet meer",
+ "Error when assembling chunks, status code {status}" : "Fout tijdens samenvoegen van brokken, status code {status}",
"Actions" : "Acties",
"Download" : "Downloaden",
"Rename" : "Naam wijzigen",
@@ -123,6 +125,7 @@
"Settings" : "Instellingen",
"Show hidden files" : "Verborgen bestanden tonen",
"WebDAV" : "WebDAV",
+ "Use this address to <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">access your Files via WebDAV</a>" : "Gebruik deze link <a href=\"%s\" target=\"_blank\" rel=\"noreferrer noopener\">om je bestanden te benaderen via WebDAV</a>",
"Cancel upload" : "Stop upload",
"No files in here" : "Hier geen bestanden",
"Upload some content or sync with your devices!" : "Upload je inhoud of synchroniseer met je apparaten!",
diff --git a/apps/files/tests/js/breadcrumbSpec.js b/apps/files/tests/js/breadcrumbSpec.js
index a26f0176f15..dd3eac017ec 100644
--- a/apps/files/tests/js/breadcrumbSpec.js
+++ b/apps/files/tests/js/breadcrumbSpec.js
@@ -43,80 +43,93 @@ describe('OCA.Files.BreadCrumb tests', function() {
var $crumbs;
bc.render();
$crumbs = bc.$el.find('.crumb');
- expect($crumbs.length).toEqual(1);
- expect($crumbs.eq(0).find('a').attr('href')).toEqual('/#0');
- expect($crumbs.eq(0).find('img').length).toEqual(1);
- expect($crumbs.eq(0).attr('data-dir')).toEqual('/');
+ // menu and home
+ expect($crumbs.length).toEqual(2);
+ expect($crumbs.eq(0).find('a').hasClass('icon-more')).toEqual(true);
+ expect($crumbs.eq(0).find('div.popovermenu').length).toEqual(1);
+ expect($crumbs.eq(0).data('dir')).not.toBeDefined();
+ expect($crumbs.eq(1).find('a').attr('href')).toEqual('/#1');
+ expect($crumbs.eq(1).find('a').hasClass('icon-home')).toEqual(true);
+ expect($crumbs.eq(1).data('dir')).toEqual('/');
});
it('Renders root when switching to root', function() {
var $crumbs;
bc.setDirectory('/somedir');
bc.setDirectory('/');
$crumbs = bc.$el.find('.crumb');
- expect($crumbs.length).toEqual(1);
- expect($crumbs.eq(0).attr('data-dir')).toEqual('/');
- });
- it('Renders last crumb with "last" class', function() {
- bc.setDirectory('/abc/def');
- expect(bc.$el.find('.crumb:last').hasClass('last')).toEqual(true);
+ expect($crumbs.length).toEqual(2);
+ expect($crumbs.eq(1).data('dir')).toEqual('/');
});
it('Renders single path section', function() {
var $crumbs;
bc.setDirectory('/somedir');
$crumbs = bc.$el.find('.crumb');
- expect($crumbs.length).toEqual(2);
- expect($crumbs.eq(0).find('a').attr('href')).toEqual('/#0');
- expect($crumbs.eq(0).find('img').length).toEqual(1);
- expect($crumbs.eq(0).attr('data-dir')).toEqual('/');
- expect($crumbs.eq(1).find('a').attr('href')).toEqual('/somedir#1');
- expect($crumbs.eq(1).find('img').length).toEqual(0);
- expect($crumbs.eq(1).attr('data-dir')).toEqual('/somedir');
+ expect($crumbs.length).toEqual(3);
+ expect($crumbs.eq(0).find('a').hasClass('icon-more')).toEqual(true);
+ expect($crumbs.eq(0).find('div.popovermenu').length).toEqual(1);
+ expect($crumbs.eq(0).data('dir')).not.toBeDefined();
+
+ expect($crumbs.eq(1).find('a').attr('href')).toEqual('/#1');
+ expect($crumbs.eq(1).find('a').hasClass('icon-home')).toEqual(true);
+ expect($crumbs.eq(1).data('dir')).toEqual('/');
+
+ expect($crumbs.eq(2).find('a').attr('href')).toEqual('/somedir#2');
+ expect($crumbs.eq(2).find('img').length).toEqual(0);
+ expect($crumbs.eq(2).data('dir')).toEqual('/somedir');
});
it('Renders multiple path sections and special chars', function() {
var $crumbs;
bc.setDirectory('/somedir/with space/abc');
$crumbs = bc.$el.find('.crumb');
- expect($crumbs.length).toEqual(4);
- expect($crumbs.eq(0).find('a').attr('href')).toEqual('/#0');
- expect($crumbs.eq(0).find('img').length).toEqual(1);
- expect($crumbs.eq(0).attr('data-dir')).toEqual('/');
+ expect($crumbs.length).toEqual(5);
+ expect($crumbs.eq(0).find('a').hasClass('icon-more')).toEqual(true);
+ expect($crumbs.eq(0).find('div.popovermenu').length).toEqual(1);
+ expect($crumbs.eq(0).data('dir')).not.toBeDefined();
- expect($crumbs.eq(1).find('a').attr('href')).toEqual('/somedir#1');
- expect($crumbs.eq(1).find('img').length).toEqual(0);
- expect($crumbs.eq(1).attr('data-dir')).toEqual('/somedir');
+ expect($crumbs.eq(1).find('a').attr('href')).toEqual('/#1');
+ expect($crumbs.eq(1).find('a').hasClass('icon-home')).toEqual(true);
+ expect($crumbs.eq(1).data('dir')).toEqual('/');
- expect($crumbs.eq(2).find('a').attr('href')).toEqual('/somedir/with space#2');
+ expect($crumbs.eq(2).find('a').attr('href')).toEqual('/somedir#2');
expect($crumbs.eq(2).find('img').length).toEqual(0);
- expect($crumbs.eq(2).attr('data-dir')).toEqual('/somedir/with space');
+ expect($crumbs.eq(2).data('dir')).toEqual('/somedir');
- expect($crumbs.eq(3).find('a').attr('href')).toEqual('/somedir/with space/abc#3');
+ expect($crumbs.eq(3).find('a').attr('href')).toEqual('/somedir/with space#3');
expect($crumbs.eq(3).find('img').length).toEqual(0);
- expect($crumbs.eq(3).attr('data-dir')).toEqual('/somedir/with space/abc');
+ expect($crumbs.eq(3).data('dir')).toEqual('/somedir/with space');
+
+ expect($crumbs.eq(4).find('a').attr('href')).toEqual('/somedir/with space/abc#4');
+ expect($crumbs.eq(4).find('img').length).toEqual(0);
+ expect($crumbs.eq(4).data('dir')).toEqual('/somedir/with space/abc');
});
it('Renders backslashes as regular directory separator', function() {
var $crumbs;
bc.setDirectory('/somedir\\with/mixed\\separators');
$crumbs = bc.$el.find('.crumb');
- expect($crumbs.length).toEqual(5);
- expect($crumbs.eq(0).find('a').attr('href')).toEqual('/#0');
- expect($crumbs.eq(0).find('img').length).toEqual(1);
- expect($crumbs.eq(0).attr('data-dir')).toEqual('/');
+ expect($crumbs.length).toEqual(6);
+ expect($crumbs.eq(0).find('a').hasClass('icon-more')).toEqual(true);
+ expect($crumbs.eq(0).find('div.popovermenu').length).toEqual(1);
+ expect($crumbs.eq(0).data('dir')).not.toBeDefined();
- expect($crumbs.eq(1).find('a').attr('href')).toEqual('/somedir#1');
- expect($crumbs.eq(1).find('img').length).toEqual(0);
- expect($crumbs.eq(1).attr('data-dir')).toEqual('/somedir');
+ expect($crumbs.eq(1).find('a').attr('href')).toEqual('/#1');
+ expect($crumbs.eq(1).find('a').hasClass('icon-home')).toEqual(true);
+ expect($crumbs.eq(1).data('dir')).toEqual('/');
- expect($crumbs.eq(2).find('a').attr('href')).toEqual('/somedir/with#2');
+ expect($crumbs.eq(2).find('a').attr('href')).toEqual('/somedir#2');
expect($crumbs.eq(2).find('img').length).toEqual(0);
- expect($crumbs.eq(2).attr('data-dir')).toEqual('/somedir/with');
+ expect($crumbs.eq(2).data('dir')).toEqual('/somedir');
- expect($crumbs.eq(3).find('a').attr('href')).toEqual('/somedir/with/mixed#3');
+ expect($crumbs.eq(3).find('a').attr('href')).toEqual('/somedir/with#3');
expect($crumbs.eq(3).find('img').length).toEqual(0);
- expect($crumbs.eq(3).attr('data-dir')).toEqual('/somedir/with/mixed');
+ expect($crumbs.eq(3).data('dir')).toEqual('/somedir/with');
- expect($crumbs.eq(4).find('a').attr('href')).toEqual('/somedir/with/mixed/separators#4');
+ expect($crumbs.eq(4).find('a').attr('href')).toEqual('/somedir/with/mixed#4');
expect($crumbs.eq(4).find('img').length).toEqual(0);
- expect($crumbs.eq(4).attr('data-dir')).toEqual('/somedir/with/mixed/separators');
+ expect($crumbs.eq(4).data('dir')).toEqual('/somedir/with/mixed');
+
+ expect($crumbs.eq(5).find('a').attr('href')).toEqual('/somedir/with/mixed/separators#5');
+ expect($crumbs.eq(5).find('img').length).toEqual(0);
+ expect($crumbs.eq(5).data('dir')).toEqual('/somedir/with/mixed/separators');
});
});
describe('Events', function() {
@@ -126,14 +139,15 @@ describe('OCA.Files.BreadCrumb tests', function() {
onClick: handler
});
bc.setDirectory('/one/two/three/four');
- bc.$el.find('.crumb:eq(3)').click();
- expect(handler.calledOnce).toEqual(true);
- expect(handler.getCall(0).thisValue).toEqual(bc.$el.find('.crumb').get(3));
+ // Click on crumb does not work, only link
+ bc.$el.find('.crumb:eq(4)').click();
+ expect(handler.calledOnce).toEqual(false);
handler.reset();
- bc.$el.find('.crumb:eq(0) a').click();
+ // Click on crumb link works
+ bc.$el.find('.crumb:eq(1) a').click();
expect(handler.calledOnce).toEqual(true);
- expect(handler.getCall(0).thisValue).toEqual(bc.$el.find('.crumb').get(0));
+ expect(handler.getCall(0).thisValue).toEqual(bc.$el.find('.crumb > a').get(1));
});
it('Calls onDrop handler when dropping on a crumb', function() {
var droppableStub = sinon.stub($.fn, 'droppable');
@@ -154,8 +168,75 @@ describe('OCA.Files.BreadCrumb tests', function() {
droppableStub.restore();
});
});
+
+ describe('Menu tests', function() {
+ var bc, dummyDir, $crumbmenuLink, $popovermenu;
+
+ beforeEach(function() {
+ dummyDir = '/one/two/three/four/five'
+
+ $('div.crumb').each(function(index){
+ $(this).css('width', 50);
+ });
+
+ bc = new BreadCrumb();
+ // append dummy navigation and controls
+ // as they are currently used for measurements
+ $('#testArea').append(
+ '<div id="controls"></div>'
+ );
+ $('#controls').append(bc.$el);
+
+ // Shrink to show popovermenu
+ bc.setMaxWidth(300);
+
+ // triggers resize implicitly
+ bc.setDirectory(dummyDir);
+
+ $crumbmenuLink = bc.$el.find('.crumbmenu > a');
+ $popovermenu = $crumbmenuLink.next('.popovermenu');
+ });
+ afterEach(function() {
+ bc = null;
+ });
+
+ it('Opens and closes the menu on click', function() {
+ // Menu exists
+ expect($popovermenu.length).toEqual(1);
+
+ // Disable jQuery delay
+ jQuery.fx.off = true
+
+ // Click on menu
+ $crumbmenuLink.click();
+ expect($popovermenu.is(':visible')).toEqual(true);
+
+ // Click on home
+ $(document).mouseup();
+ expect($popovermenu.is(':visible')).toEqual(false);
+
+ // Change directory and reset elements
+ bc.setDirectory('/one/two/three/four/five/six/seven/eight/nine/ten');
+ $crumbmenuLink = bc.$el.find('.crumbmenu > a');
+ $popovermenu = $crumbmenuLink.next('.popovermenu');
+
+ // Click on menu again
+ $crumbmenuLink.click();
+ expect($popovermenu.is(':visible')).toEqual(true);
+
+ // Click on home again
+ $(document).mouseup();
+ expect($popovermenu.is(':visible')).toEqual(false);
+
+ });
+ it('Shows only items not in the breadcrumb', function() {
+ var hiddenCrumbs = bc.$el.find('.crumb:not(.crumbmenu).hidden');
+ expect($popovermenu.find('li:not(.in-breadcrumb)').length).toEqual(hiddenCrumbs.length);
+ });
+ });
+
describe('Resizing', function() {
- var bc, dummyDir, widths, oldUpdateTotalWidth;
+ var bc, dummyDir, widths;
beforeEach(function() {
dummyDir = '/short name/longer name/looooooooooooonger/' +
@@ -163,17 +244,12 @@ describe('OCA.Files.BreadCrumb tests', function() {
// using hard-coded widths (pre-measured) to avoid getting different
// results on different browsers due to font engine differences
- widths = [41, 106, 112, 160, 257, 251, 91];
+ // 51px is default size for menu and home
+ widths = [51, 51, 106, 112, 160, 257, 251, 91];
- oldUpdateTotalWidth = BreadCrumb.prototype._updateTotalWidth;
- BreadCrumb.prototype._updateTotalWidth = function() {
- // pre-set a width to simulate consistent measurement
- $('div.crumb').each(function(index){
- $(this).css('width', widths[index]);
- });
-
- return oldUpdateTotalWidth.apply(this, arguments);
- };
+ $('div.crumb').each(function(index){
+ $(this).css('width', widths[index]);
+ });
bc = new BreadCrumb();
// append dummy navigation and controls
@@ -184,30 +260,26 @@ describe('OCA.Files.BreadCrumb tests', function() {
$('#controls').append(bc.$el);
});
afterEach(function() {
- BreadCrumb.prototype._updateTotalWidth = oldUpdateTotalWidth;
bc = null;
});
it('Hides breadcrumbs to fit max allowed width', function() {
var $crumbs;
bc.setMaxWidth(500);
+
// triggers resize implicitly
bc.setDirectory(dummyDir);
$crumbs = bc.$el.find('.crumb');
- // first one is always visible
+ // Menu and home are always visible
expect($crumbs.eq(0).hasClass('hidden')).toEqual(false);
- // second one has ellipsis
expect($crumbs.eq(1).hasClass('hidden')).toEqual(false);
- expect($crumbs.eq(1).find('.ellipsis').length).toEqual(1);
- // there is only one ellipsis in total
- expect($crumbs.find('.ellipsis').length).toEqual(1);
- // subsequent elements are hidden
- expect($crumbs.eq(2).hasClass('hidden')).toEqual(true);
+
+ expect($crumbs.eq(2).hasClass('hidden')).toEqual(false);
expect($crumbs.eq(3).hasClass('hidden')).toEqual(true);
expect($crumbs.eq(4).hasClass('hidden')).toEqual(true);
expect($crumbs.eq(5).hasClass('hidden')).toEqual(true);
- expect($crumbs.eq(6).hasClass('hidden')).toEqual(false);
+ expect($crumbs.eq(6).hasClass('hidden')).toEqual(true);
expect($crumbs.eq(7).hasClass('hidden')).toEqual(false);
});
it('Updates the breadcrumbs when reducing max allowed width', function() {
@@ -215,56 +287,27 @@ describe('OCA.Files.BreadCrumb tests', function() {
// enough space
bc.setMaxWidth(1800);
+ $crumbs = bc.$el.find('.crumb');
- expect(bc.$el.find('.ellipsis').length).toEqual(0);
+ // Menu is hidden
+ expect($crumbs.eq(0).hasClass('hidden')).toEqual(false);
// triggers resize implicitly
bc.setDirectory(dummyDir);
- // simulate increase
+ // simulate decrease
bc.setMaxWidth(950);
- $crumbs = bc.$el.find('.crumb');
- // first one is always visible
+ // Menu and home are always visible
expect($crumbs.eq(0).hasClass('hidden')).toEqual(false);
- // second one has ellipsis
expect($crumbs.eq(1).hasClass('hidden')).toEqual(false);
- expect($crumbs.eq(1).find('.ellipsis').length).toEqual(1);
- // there is only one ellipsis in total
- expect($crumbs.find('.ellipsis').length).toEqual(1);
- // subsequent elements are hidden
- expect($crumbs.eq(2).hasClass('hidden')).toEqual(true);
- expect($crumbs.eq(3).hasClass('hidden')).toEqual(true);
- // the rest is visible
- expect($crumbs.eq(4).hasClass('hidden')).toEqual(false);
- expect($crumbs.eq(5).hasClass('hidden')).toEqual(false);
- expect($crumbs.eq(6).hasClass('hidden')).toEqual(false);
- });
- it('Removes the ellipsis when there is enough space', function() {
- var $crumbs;
-
- bc.setMaxWidth(500);
- // triggers resize implicitly
- bc.setDirectory(dummyDir);
- $crumbs = bc.$el.find('.crumb');
-
- // ellipsis
- expect(bc.$el.find('.ellipsis').length).toEqual(1);
-
- // simulate increase
- bc.setMaxWidth(1800);
- // no ellipsis
- expect(bc.$el.find('.ellipsis').length).toEqual(0);
-
- // all are visible
- expect($crumbs.eq(0).hasClass('hidden')).toEqual(false);
- expect($crumbs.eq(1).hasClass('hidden')).toEqual(false);
expect($crumbs.eq(2).hasClass('hidden')).toEqual(false);
expect($crumbs.eq(3).hasClass('hidden')).toEqual(false);
expect($crumbs.eq(4).hasClass('hidden')).toEqual(false);
expect($crumbs.eq(5).hasClass('hidden')).toEqual(false);
expect($crumbs.eq(6).hasClass('hidden')).toEqual(false);
+ expect($crumbs.eq(7).hasClass('hidden')).toEqual(false);
});
});
});
diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js
index fd011474eb1..c590275e1cf 100644
--- a/apps/files/tests/js/filelistSpec.js
+++ b/apps/files/tests/js/filelistSpec.js
@@ -1657,7 +1657,7 @@ describe('OCA.Files.FileList tests', function() {
fileList.changeDirectory('/subdir/two/three with space/four/five');
deferredList.resolve(200, [testRoot].concat(testFiles));
var changeDirStub = sinon.stub(fileList, 'changeDirectory');
- fileList.breadcrumb.$el.find('.crumb:eq(0)').trigger({type: 'click', which: 1});
+ fileList.breadcrumb.$el.find('.crumb:eq(1) > a').trigger({type: 'click', which: 1});
expect(changeDirStub.calledOnce).toEqual(true);
expect(changeDirStub.getCall(0).args[0]).toEqual('/');
@@ -1667,7 +1667,7 @@ describe('OCA.Files.FileList tests', function() {
fileList.changeDirectory('/subdir/two/three with space/four/five');
deferredList.resolve(200, [testRoot].concat(testFiles));
var changeDirStub = sinon.stub(fileList, 'changeDirectory');
- fileList.breadcrumb.$el.find('.crumb:eq(3)').trigger({type: 'click', which: 1});
+ fileList.breadcrumb.$el.find('.crumb:eq(4) > a').trigger({type: 'click', which: 1});
expect(changeDirStub.calledOnce).toEqual(true);
expect(changeDirStub.getCall(0).args[0]).toEqual('/subdir/two/three with space');
@@ -1678,7 +1678,7 @@ describe('OCA.Files.FileList tests', function() {
var moveStub = sinon.stub(filesClient, 'move').returns($.Deferred().promise());
fileList.changeDirectory(testDir);
deferredList.resolve(200, [testRoot].concat(testFiles));
- var $crumb = fileList.breadcrumb.$el.find('.crumb:eq(3)');
+ var $crumb = fileList.breadcrumb.$el.find('.crumb:eq(4)');
// no idea what this is but is required by the handler
var ui = {
helper: {
@@ -3013,7 +3013,7 @@ describe('OCA.Files.FileList tests', function() {
it('drop on a breadcrumb inside the table triggers upload to target folder', function() {
var ev;
fileList.changeDirectory('a/b/c/d');
- ev = dropOn(fileList.$el.find('.crumb:eq(2)'), uploadData);
+ ev = dropOn(fileList.$el.find('.crumb:eq(3)'), uploadData);
expect(ev).not.toEqual(false);
expect(uploadData.targetDir).toEqual('/a/b');
diff --git a/apps/files_external/3rdparty/composer.json b/apps/files_external/3rdparty/composer.json
index f1613f0c70b..307a062c7e0 100644
--- a/apps/files_external/3rdparty/composer.json
+++ b/apps/files_external/3rdparty/composer.json
@@ -8,7 +8,7 @@
"classmap-authoritative": true
},
"require": {
- "icewind/smb": "2.0.2",
+ "icewind/smb": "2.0.3",
"icewind/streams": "0.5.2"
}
}
diff --git a/apps/files_external/3rdparty/composer.lock b/apps/files_external/3rdparty/composer.lock
index 0cf5cabdc19..e00a7bd80e4 100644
--- a/apps/files_external/3rdparty/composer.lock
+++ b/apps/files_external/3rdparty/composer.lock
@@ -4,20 +4,20 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
- "content-hash": "85f8c3519f909ded38d917d3901f2709",
+ "content-hash": "b6a304e8ab2effa3791b513007fadcbc",
"packages": [
{
"name": "icewind/smb",
- "version": "v2.0.2",
+ "version": "v2.0.3",
"source": {
"type": "git",
"url": "https://github.com/icewind1991/SMB.git",
- "reference": "6691355d9314ac3a8cb9ec9446e4c26e8aab09d0"
+ "reference": "8394551bf29a37b884edb33dae8acde369177f32"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/icewind1991/SMB/zipball/6691355d9314ac3a8cb9ec9446e4c26e8aab09d0",
- "reference": "6691355d9314ac3a8cb9ec9446e4c26e8aab09d0",
+ "url": "https://api.github.com/repos/icewind1991/SMB/zipball/8394551bf29a37b884edb33dae8acde369177f32",
+ "reference": "8394551bf29a37b884edb33dae8acde369177f32",
"shasum": ""
},
"require": {
@@ -45,7 +45,7 @@
}
],
"description": "php wrapper for smbclient and libsmbclient-php",
- "time": "2017-08-16T16:08:57+00:00"
+ "time": "2017-10-18T16:21:10+00:00"
},
{
"name": "icewind/streams",
diff --git a/apps/files_external/3rdparty/composer/autoload_classmap.php b/apps/files_external/3rdparty/composer/autoload_classmap.php
index 4c596a44418..257bdb64eb5 100644
--- a/apps/files_external/3rdparty/composer/autoload_classmap.php
+++ b/apps/files_external/3rdparty/composer/autoload_classmap.php
@@ -22,6 +22,7 @@ return array(
'Icewind\\SMB\\Exception\\ForbiddenException' => $vendorDir . '/icewind/smb/src/Exception/ForbiddenException.php',
'Icewind\\SMB\\Exception\\HostDownException' => $vendorDir . '/icewind/smb/src/Exception/HostDownException.php',
'Icewind\\SMB\\Exception\\InvalidHostException' => $vendorDir . '/icewind/smb/src/Exception/InvalidHostException.php',
+ 'Icewind\\SMB\\Exception\\InvalidParameterException' => $vendorDir . '/icewind/smb/src/Exception/InvalidParameterException.php',
'Icewind\\SMB\\Exception\\InvalidPathException' => $vendorDir . '/icewind/smb/src/Exception/InvalidPathException.php',
'Icewind\\SMB\\Exception\\InvalidRequestException' => $vendorDir . '/icewind/smb/src/Exception/InvalidRequestException.php',
'Icewind\\SMB\\Exception\\InvalidResourceException' => $vendorDir . '/icewind/smb/src/Exception/InvalidResourceException.php',
@@ -30,6 +31,8 @@ return array(
'Icewind\\SMB\\Exception\\NoRouteToHostException' => $vendorDir . '/icewind/smb/src/Exception/NoRouteToHostException.php',
'Icewind\\SMB\\Exception\\NotEmptyException' => $vendorDir . '/icewind/smb/src/Exception/NotEmptyException.php',
'Icewind\\SMB\\Exception\\NotFoundException' => $vendorDir . '/icewind/smb/src/Exception/NotFoundException.php',
+ 'Icewind\\SMB\\Exception\\OutOfSpaceException' => $vendorDir . '/icewind/smb/src/Exception/OutOfSpaceException.php',
+ 'Icewind\\SMB\\Exception\\RevisionMismatchException' => $vendorDir . '/icewind/smb/src/Exception/RevisionMismatchException.php',
'Icewind\\SMB\\Exception\\TimedOutException' => $vendorDir . '/icewind/smb/src/Exception/TimedOutException.php',
'Icewind\\SMB\\FileInfo' => $vendorDir . '/icewind/smb/src/FileInfo.php',
'Icewind\\SMB\\IFileInfo' => $vendorDir . '/icewind/smb/src/IFileInfo.php',
diff --git a/apps/files_external/3rdparty/composer/autoload_static.php b/apps/files_external/3rdparty/composer/autoload_static.php
index 459de971c4e..62be2df6a0d 100644
--- a/apps/files_external/3rdparty/composer/autoload_static.php
+++ b/apps/files_external/3rdparty/composer/autoload_static.php
@@ -52,6 +52,7 @@ class ComposerStaticInit98fe9b281934250b3a93f69a5ce843b3
'Icewind\\SMB\\Exception\\ForbiddenException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/ForbiddenException.php',
'Icewind\\SMB\\Exception\\HostDownException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/HostDownException.php',
'Icewind\\SMB\\Exception\\InvalidHostException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/InvalidHostException.php',
+ 'Icewind\\SMB\\Exception\\InvalidParameterException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/InvalidParameterException.php',
'Icewind\\SMB\\Exception\\InvalidPathException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/InvalidPathException.php',
'Icewind\\SMB\\Exception\\InvalidRequestException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/InvalidRequestException.php',
'Icewind\\SMB\\Exception\\InvalidResourceException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/InvalidResourceException.php',
@@ -60,6 +61,8 @@ class ComposerStaticInit98fe9b281934250b3a93f69a5ce843b3
'Icewind\\SMB\\Exception\\NoRouteToHostException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/NoRouteToHostException.php',
'Icewind\\SMB\\Exception\\NotEmptyException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/NotEmptyException.php',
'Icewind\\SMB\\Exception\\NotFoundException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/NotFoundException.php',
+ 'Icewind\\SMB\\Exception\\OutOfSpaceException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/OutOfSpaceException.php',
+ 'Icewind\\SMB\\Exception\\RevisionMismatchException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/RevisionMismatchException.php',
'Icewind\\SMB\\Exception\\TimedOutException' => __DIR__ . '/..' . '/icewind/smb/src/Exception/TimedOutException.php',
'Icewind\\SMB\\FileInfo' => __DIR__ . '/..' . '/icewind/smb/src/FileInfo.php',
'Icewind\\SMB\\IFileInfo' => __DIR__ . '/..' . '/icewind/smb/src/IFileInfo.php',
diff --git a/apps/files_external/3rdparty/composer/installed.json b/apps/files_external/3rdparty/composer/installed.json
index aafe1591fa8..6855971a9f1 100644
--- a/apps/files_external/3rdparty/composer/installed.json
+++ b/apps/files_external/3rdparty/composer/installed.json
@@ -44,17 +44,17 @@
},
{
"name": "icewind/smb",
- "version": "v2.0.2",
- "version_normalized": "2.0.2.0",
+ "version": "v2.0.3",
+ "version_normalized": "2.0.3.0",
"source": {
"type": "git",
"url": "https://github.com/icewind1991/SMB.git",
- "reference": "6691355d9314ac3a8cb9ec9446e4c26e8aab09d0"
+ "reference": "8394551bf29a37b884edb33dae8acde369177f32"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/icewind1991/SMB/zipball/6691355d9314ac3a8cb9ec9446e4c26e8aab09d0",
- "reference": "6691355d9314ac3a8cb9ec9446e4c26e8aab09d0",
+ "url": "https://api.github.com/repos/icewind1991/SMB/zipball/8394551bf29a37b884edb33dae8acde369177f32",
+ "reference": "8394551bf29a37b884edb33dae8acde369177f32",
"shasum": ""
},
"require": {
@@ -64,7 +64,7 @@
"require-dev": {
"phpunit/phpunit": "^4.8"
},
- "time": "2017-08-16T16:08:57+00:00",
+ "time": "2017-10-18T16:21:10+00:00",
"type": "library",
"installation-source": "source",
"autoload": {
diff --git a/apps/files_external/3rdparty/icewind/smb/src/ErrorCodes.php b/apps/files_external/3rdparty/icewind/smb/src/ErrorCodes.php
index 03bd574c185..d36cdaf2c7d 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/ErrorCodes.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/ErrorCodes.php
@@ -15,7 +15,7 @@ class ErrorCodes {
const BadHostName = 'NT_STATUS_BAD_NETWORK_NAME';
const Unsuccessful = 'NT_STATUS_UNSUCCESSFUL';
const ConnectionRefused = 'NT_STATUS_CONNECTION_REFUSED';
- const NoLogonServers = 'NT_STATUS_NO_LOGON_SERVERS';
+ const NoLogonServers = 'NT_STATUS_NO_LOGON_SERVERS';
const PathNotFound = 'NT_STATUS_OBJECT_PATH_NOT_FOUND';
const NoSuchFile = 'NT_STATUS_NO_SUCH_FILE';
@@ -26,4 +26,6 @@ class ErrorCodes {
const FileIsADirectory = 'NT_STATUS_FILE_IS_A_DIRECTORY';
const NotADirectory = 'NT_STATUS_NOT_A_DIRECTORY';
const SharingViolation = 'NT_STATUS_SHARING_VIOLATION';
+ const InvalidParameter = 'NT_STATUS_INVALID_PARAMETER';
+ const RevisionMismatch = 'NT_STATUS_REVISION_MISMATCH';
}
diff --git a/apps/files_external/3rdparty/icewind/smb/src/Exception/Exception.php b/apps/files_external/3rdparty/icewind/smb/src/Exception/Exception.php
index 7ac528198a9..93f2c1b3e2e 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/Exception/Exception.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/Exception/Exception.php
@@ -14,7 +14,7 @@ class Exception extends \Exception {
$message .= ' for ' . $path;
}
- return new Exception($message, $error);
+ return new Exception($message, is_string($error) ? 0 : $error);
}
/**
diff --git a/apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidParameterException.php b/apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidParameterException.php
new file mode 100644
index 00000000000..163b571183d
--- /dev/null
+++ b/apps/files_external/3rdparty/icewind/smb/src/Exception/InvalidParameterException.php
@@ -0,0 +1,10 @@
+<?php
+/**
+ * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Licensed under the MIT license:
+ * http://opensource.org/licenses/MIT
+ */
+
+namespace Icewind\SMB\Exception;
+
+class InvalidParameterException extends InvalidRequestException {}
diff --git a/apps/files_external/3rdparty/icewind/smb/src/Exception/OutOfSpaceException.php b/apps/files_external/3rdparty/icewind/smb/src/Exception/OutOfSpaceException.php
new file mode 100644
index 00000000000..4c5517a1404
--- /dev/null
+++ b/apps/files_external/3rdparty/icewind/smb/src/Exception/OutOfSpaceException.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Licensed under the MIT license:
+ * http://opensource.org/licenses/MIT
+ */
+
+namespace Icewind\SMB\Exception;
+
+class OutOfSpaceException extends InvalidRequestException {
+}
diff --git a/apps/files_external/3rdparty/icewind/smb/src/Exception/RevisionMismatchException.php b/apps/files_external/3rdparty/icewind/smb/src/Exception/RevisionMismatchException.php
new file mode 100644
index 00000000000..e898b5a2347
--- /dev/null
+++ b/apps/files_external/3rdparty/icewind/smb/src/Exception/RevisionMismatchException.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
+ * This file is licensed under the Licensed under the MIT license:
+ * http://opensource.org/licenses/MIT
+ */
+
+namespace Icewind\SMB\Exception;
+
+use Throwable;
+
+class RevisionMismatchException extends Exception {
+ public function __construct($message = 'Protocol version mismatch', $code = 0, Throwable $previous = null) {
+ parent::__construct($message, $code, $previous);
+ }
+}
diff --git a/apps/files_external/3rdparty/icewind/smb/src/NativeState.php b/apps/files_external/3rdparty/icewind/smb/src/NativeState.php
index 7ddce831853..45e0441d252 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/NativeState.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/NativeState.php
@@ -31,6 +31,7 @@ class NativeState {
17 => '\Icewind\SMB\Exception\AlreadyExistsException',
20 => '\Icewind\SMB\Exception\InvalidTypeException',
21 => '\Icewind\SMB\Exception\InvalidTypeException',
+ 28 => '\Icewind\SMB\Exception\OutOfSpaceException',
39 => '\Icewind\SMB\Exception\NotEmptyException',
110 => '\Icewind\SMB\Exception\TimedOutException',
111 => '\Icewind\SMB\Exception\ConnectionRefusedException',
diff --git a/apps/files_external/3rdparty/icewind/smb/src/NotifyHandler.php b/apps/files_external/3rdparty/icewind/smb/src/NotifyHandler.php
index 6ad565555bf..20ada5cf320 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/NotifyHandler.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/NotifyHandler.php
@@ -9,6 +9,8 @@
namespace Icewind\SMB;
+use Icewind\SMB\Exception\Exception;
+
class NotifyHandler implements INotifyHandler {
/**
* @var Connection
@@ -22,6 +24,12 @@ class NotifyHandler implements INotifyHandler {
private $listening = true;
+ // todo replace with static once <5.6 support is dropped
+ // see error.h
+ private static $exceptionMap = [
+ ErrorCodes::RevisionMismatch => '\Icewind\SMB\Exception\RevisionMismatchException',
+ ];
+
/**
* @param Connection $connection
* @param string $path
@@ -43,6 +51,7 @@ class NotifyHandler implements INotifyHandler {
stream_set_blocking($this->connection->getOutputStream(), 0);
$lines = [];
while (($line = $this->connection->readLine())) {
+ $this->checkForError($line);
$lines[] = $line;
}
stream_set_blocking($this->connection->getOutputStream(), 1);
@@ -59,6 +68,7 @@ class NotifyHandler implements INotifyHandler {
public function listen($callback) {
if ($this->listening) {
$this->connection->read(function ($line) use ($callback) {
+ $this->checkForError($line);
$change = $this->parseChangeLine($line);
if ($change) {
return $callback($change);
@@ -80,6 +90,13 @@ class NotifyHandler implements INotifyHandler {
}
}
+ private function checkForError($line) {
+ if (substr($line, 0, 16) === 'notify returned ') {
+ $error = substr($line, 16);
+ throw Exception::fromMap(self::$exceptionMap, $error, 'Notify is not supported with the used smb version');
+ }
+ }
+
public function stop() {
$this->listening = false;
$this->connection->close();
diff --git a/apps/files_external/3rdparty/icewind/smb/src/Parser.php b/apps/files_external/3rdparty/icewind/smb/src/Parser.php
index 5cc5acbdf56..3142f9c29e0 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/Parser.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/Parser.php
@@ -30,6 +30,7 @@ class Parser {
// todo replace with static once <5.6 support is dropped
// see error.h
private static $exceptionMap = [
+ ErrorCodes::LogonFailure => '\Icewind\SMB\Exception\AuthenticationException',
ErrorCodes::PathNotFound => '\Icewind\SMB\Exception\NotFoundException',
ErrorCodes::ObjectNotFound => '\Icewind\SMB\Exception\NotFoundException',
ErrorCodes::NoSuchFile => '\Icewind\SMB\Exception\NotFoundException',
@@ -38,7 +39,8 @@ class Parser {
ErrorCodes::DirectoryNotEmpty => '\Icewind\SMB\Exception\NotEmptyException',
ErrorCodes::FileIsADirectory => '\Icewind\SMB\Exception\InvalidTypeException',
ErrorCodes::NotADirectory => '\Icewind\SMB\Exception\InvalidTypeException',
- ErrorCodes::SharingViolation => '\Icewind\SMB\Exception\FileInUseException'
+ ErrorCodes::SharingViolation => '\Icewind\SMB\Exception\FileInUseException',
+ ErrorCodes::InvalidParameter => '\Icewind\SMB\Exception\InvalidParameterException'
];
/**
diff --git a/apps/files_external/3rdparty/icewind/smb/src/RawConnection.php b/apps/files_external/3rdparty/icewind/smb/src/RawConnection.php
index e9349716430..42923f09eda 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/RawConnection.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/RawConnection.php
@@ -7,6 +7,7 @@
namespace Icewind\SMB;
+use Icewind\SMB\Exception\ConnectException;
use Icewind\SMB\Exception\ConnectionException;
class RawConnection {
@@ -25,6 +26,9 @@ class RawConnection {
*
* $pipes[0] holds STDIN for smbclient
* $pipes[1] holds STDOUT for smbclient
+ * $pipes[3] holds the authfile for smbclient
+ * $pipes[4] holds the stream for writing files
+ * $pipes[5] holds the stream for reading files
*/
private $pipes;
@@ -33,32 +37,44 @@ class RawConnection {
*/
private $process;
- public function __construct($command, $env = array()) {
+ /**
+ * @var resource|null $authStream
+ */
+ private $authStream = null;
+
+ private $connected = false;
+
+ public function __construct($command, array $env = []) {
$this->command = $command;
$this->env = $env;
- $this->connect();
}
- private function connect() {
- $descriptorSpec = array(
- 0 => array('pipe', 'r'), // child reads from stdin
- 1 => array('pipe', 'w'), // child writes to stdout
- 2 => array('pipe', 'w'), // child writes to stderr
- 3 => array('pipe', 'r'), // child reads from fd#3
- 4 => array('pipe', 'r'), // child reads from fd#4
- 5 => array('pipe', 'w') // child writes to fd#5
- );
+ public function connect() {
+ if (is_null($this->getAuthStream())) {
+ throw new ConnectException('Authentication not set before connecting');
+ }
+
+ $descriptorSpec = [
+ 0 => ['pipe', 'r'], // child reads from stdin
+ 1 => ['pipe', 'w'], // child writes to stdout
+ 2 => ['pipe', 'w'], // child writes to stderr
+ 3 => $this->getAuthStream(), // child reads from fd#3
+ 4 => ['pipe', 'r'], // child reads from fd#4
+ 5 => ['pipe', 'w'] // child writes to fd#5
+ ];
+
setlocale(LC_ALL, Server::LOCALE);
- $env = array_merge($this->env, array(
+ $env = array_merge($this->env, [
'CLI_FORCE_INTERACTIVE' => 'y', // Needed or the prompt isn't displayed!!
- 'LC_ALL' => Server::LOCALE,
- 'LANG' => Server::LOCALE,
- 'COLUMNS' => 8192 // prevent smbclient from line-wrapping it's output
- ));
+ 'LC_ALL' => Server::LOCALE,
+ 'LANG' => Server::LOCALE,
+ 'COLUMNS' => 8192 // prevent smbclient from line-wrapping it's output
+ ]);
$this->process = proc_open($this->command, $descriptorSpec, $this->pipes, '/', $env);
if (!$this->isValid()) {
throw new ConnectionException();
}
+ $this->connected = true;
}
/**
@@ -129,7 +145,7 @@ class RawConnection {
}
public function getAuthStream() {
- return $this->pipes[3];
+ return $this->authStream;
}
public function getFileInputStream() {
@@ -143,14 +159,10 @@ class RawConnection {
public function writeAuthentication($user, $password) {
$auth = ($password === false)
? "username=$user"
- : "username=$user\npassword=$password";
+ : "username=$user\npassword=$password\n";
- if (fwrite($this->getAuthStream(), $auth) === false) {
- fclose($this->getAuthStream());
- return false;
- }
- fclose($this->getAuthStream());
- return true;
+ $this->authStream = fopen('php://temp', 'w+');
+ fwrite($this->getAuthStream(), $auth);
}
public function close($terminate = true) {
@@ -163,8 +175,8 @@ class RawConnection {
$status = proc_get_status($this->process);
$ppid = $status['pid'];
$pids = preg_split('/\s+/', `ps -o pid --no-heading --ppid $ppid`);
- foreach($pids as $pid) {
- if(is_numeric($pid)) {
+ foreach ($pids as $pid) {
+ if (is_numeric($pid)) {
//9 is the SIGKILL signal
posix_kill($pid, 9);
}
diff --git a/apps/files_external/3rdparty/icewind/smb/src/Server.php b/apps/files_external/3rdparty/icewind/smb/src/Server.php
index 12692eb4c6e..21cc605ed1f 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/Server.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/Server.php
@@ -134,6 +134,7 @@ class Server {
);
$connection = new RawConnection($command);
$connection->writeAuthentication($this->getUser(), $this->getPassword());
+ $connection->connect();
$output = $connection->readAll();
$parser = new Parser($this->timezoneProvider);
diff --git a/apps/files_external/3rdparty/icewind/smb/src/Share.php b/apps/files_external/3rdparty/icewind/smb/src/Share.php
index ba8bbbbb8ca..542eaf0887e 100644
--- a/apps/files_external/3rdparty/icewind/smb/src/Share.php
+++ b/apps/files_external/3rdparty/icewind/smb/src/Share.php
@@ -68,8 +68,9 @@ class Share extends AbstractShare {
);
$connection = new Connection($command, $this->parser);
$connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
+ $connection->connect();
if (!$connection->isValid()) {
- throw new ConnectionException();
+ throw new ConnectionException($connection->readLine());
}
return $connection;
}
@@ -88,7 +89,6 @@ class Share extends AbstractShare {
protected function reconnect() {
$this->connection->reconnect();
- $this->connection->writeAuthentication($this->server->getUser(), $this->server->getPassword());
if (!$this->connection->isValid()) {
throw new ConnectionException();
}
@@ -318,9 +318,9 @@ class Share extends AbstractShare {
$modeString = '';
$modeMap = array(
FileInfo::MODE_READONLY => 'r',
- FileInfo::MODE_HIDDEN => 'h',
- FileInfo::MODE_ARCHIVE => 'a',
- FileInfo::MODE_SYSTEM => 's'
+ FileInfo::MODE_HIDDEN => 'h',
+ FileInfo::MODE_ARCHIVE => 'a',
+ FileInfo::MODE_SYSTEM => 's'
);
foreach ($modeMap as $modeByte => $string) {
if ($mode & $modeByte) {
@@ -413,6 +413,7 @@ class Share extends AbstractShare {
}
$path = str_replace('/', '\\', $path);
$path = str_replace('"', '^"', $path);
+ $path = ltrim($path, '\\');
return '"' . $path . '"';
}
diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php
index 1d703e0c1b3..237985bfd0f 100644
--- a/apps/files_external/templates/settings.php
+++ b/apps/files_external/templates/settings.php
@@ -169,10 +169,10 @@
<?php if ($_['visibilityType'] === BackendService::VISIBILITY_ADMIN): ?>
<input type="checkbox" name="allowUserMounting" id="allowUserMounting" class="checkbox"
- value="1" <?php if ($_['allowUserMounting'] === 'yes') print_unescaped(' checked="checked"'); ?> />
+ value="1" <?php if ($_['allowUserMounting']) print_unescaped(' checked="checked"'); ?> />
<label for="allowUserMounting"><?php p($l->t('Allow users to mount external storage')); ?></label> <span id="userMountingMsg" class="msg"></span>
- <p id="userMountingBackends"<?php if ($_['allowUserMounting'] !== 'yes'): ?> class="hidden"<?php endif; ?>>
+ <p id="userMountingBackends"<?php if (!$_['allowUserMounting']): ?> class="hidden"<?php endif; ?>>
<?php p($l->t('Allow users to mount the following external storage')); ?><br />
<?php
$userBackends = array_filter($_['backends'], function($backend) {
diff --git a/apps/files_trashbin/tests/js/filelistSpec.js b/apps/files_trashbin/tests/js/filelistSpec.js
index 5e9a4cf27d1..04ff243d07b 100644
--- a/apps/files_trashbin/tests/js/filelistSpec.js
+++ b/apps/files_trashbin/tests/js/filelistSpec.js
@@ -132,12 +132,12 @@ describe('OCA.Trashbin.FileList tests', function() {
fileList.changeDirectory('/subdir', false, true);
fakeServer.respond();
var $crumbs = fileList.$el.find('#controls .crumb');
- expect($crumbs.length).toEqual(2);
- expect($crumbs.eq(0).find('a').text()).toEqual('');
- expect($crumbs.eq(0).find('a').attr('href'))
- .toEqual(OC.webroot + '/index.php/apps/files?view=trashbin&dir=/');
- expect($crumbs.eq(1).find('a').text()).toEqual('subdir');
+ expect($crumbs.length).toEqual(3);
+ expect($crumbs.eq(1).find('a').text()).toEqual('Home');
expect($crumbs.eq(1).find('a').attr('href'))
+ .toEqual(OC.webroot + '/index.php/apps/files?view=trashbin&dir=/');
+ expect($crumbs.eq(2).find('a').text()).toEqual('subdir');
+ expect($crumbs.eq(2).find('a').attr('href'))
.toEqual(OC.webroot + '/index.php/apps/files?view=trashbin&dir=/subdir');
});
});
diff --git a/apps/theming/appinfo/info.xml b/apps/theming/appinfo/info.xml
index ee3126c0781..883dfbbb2ec 100644
--- a/apps/theming/appinfo/info.xml
+++ b/apps/theming/appinfo/info.xml
@@ -5,7 +5,7 @@
<description>Adjust the Nextcloud theme</description>
<licence>AGPL</licence>
<author>Nextcloud</author>
- <version>1.4.0</version>
+ <version>1.4.1</version>
<namespace>Theming</namespace>
<category>other</category>
diff --git a/apps/theming/l10n/es_CL.js b/apps/theming/l10n/es_CL.js
index 4f98160b142..fba2c6263c0 100644
--- a/apps/theming/l10n/es_CL.js
+++ b/apps/theming/l10n/es_CL.js
@@ -33,6 +33,7 @@ OC.L10N.register(
"Login image" : "Imágen de inicio de sesión",
"Upload new login background" : "Cargar nueva imagen de fondo para inicio de sesión",
"Remove background image" : "Eliminar imagen de fondo",
+ "Install the Imagemagick PHP extension with support for SVG images to automatically generate favicons based on the uploaded logo and color." : "Instala la extensión Imagemagick de PHP con soporte a imagenes SVG para generar los favicons en automático con base en el logotipo cargado y el color.",
"reset to default" : "restaurar a predeterminado",
"Log in image" : "Imagen de inicio de sesión"
},
diff --git a/apps/theming/l10n/es_CL.json b/apps/theming/l10n/es_CL.json
index 866eb07f7fa..d0be021859a 100644
--- a/apps/theming/l10n/es_CL.json
+++ b/apps/theming/l10n/es_CL.json
@@ -31,6 +31,7 @@
"Login image" : "Imágen de inicio de sesión",
"Upload new login background" : "Cargar nueva imagen de fondo para inicio de sesión",
"Remove background image" : "Eliminar imagen de fondo",
+ "Install the Imagemagick PHP extension with support for SVG images to automatically generate favicons based on the uploaded logo and color." : "Instala la extensión Imagemagick de PHP con soporte a imagenes SVG para generar los favicons en automático con base en el logotipo cargado y el color.",
"reset to default" : "restaurar a predeterminado",
"Log in image" : "Imagen de inicio de sesión"
},"pluralForm" :"nplurals=2; plural=(n != 1);"
diff --git a/apps/theming/l10n/ru.js b/apps/theming/l10n/ru.js
index 2a46add3c0d..18c907f6cea 100644
--- a/apps/theming/l10n/ru.js
+++ b/apps/theming/l10n/ru.js
@@ -33,6 +33,7 @@ OC.L10N.register(
"Login image" : "Изображение экрана входа в систему",
"Upload new login background" : "Загрузить новый фон для экрана входа в систему",
"Remove background image" : "Убрать фоновое изображение ",
+ "Install the Imagemagick PHP extension with support for SVG images to automatically generate favicons based on the uploaded logo and color." : "Для автоматической генерации favicon на основе загруженного логотипа и цвета нужно установить PHP расширение Imagemagick с поддержкой изображений SVG ",
"reset to default" : "сброс до настроек по-умолчанию",
"Log in image" : "Изображение экрана входа в систему"
},
diff --git a/apps/theming/l10n/ru.json b/apps/theming/l10n/ru.json
index f363f3ab151..2d996c8f3e5 100644
--- a/apps/theming/l10n/ru.json
+++ b/apps/theming/l10n/ru.json
@@ -31,6 +31,7 @@
"Login image" : "Изображение экрана входа в систему",
"Upload new login background" : "Загрузить новый фон для экрана входа в систему",
"Remove background image" : "Убрать фоновое изображение ",
+ "Install the Imagemagick PHP extension with support for SVG images to automatically generate favicons based on the uploaded logo and color." : "Для автоматической генерации favicon на основе загруженного логотипа и цвета нужно установить PHP расширение Imagemagick с поддержкой изображений SVG ",
"reset to default" : "сброс до настроек по-умолчанию",
"Log in image" : "Изображение экрана входа в систему"
},"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"
diff --git a/apps/theming/lib/IconBuilder.php b/apps/theming/lib/IconBuilder.php
index 83258341985..ad44dd7ed6c 100644
--- a/apps/theming/lib/IconBuilder.php
+++ b/apps/theming/lib/IconBuilder.php
@@ -55,14 +55,38 @@ class IconBuilder {
* @return string|false image blob
*/
public function getFavicon($app) {
+ if (!$this->themingDefaults->shouldReplaceIcons()) {
+ return false;
+ }
try {
- $icon = $this->renderAppIcon($app, 32);
+ $favicon = new Imagick();
+ $favicon->setFormat("ico");
+ $icon = $this->renderAppIcon($app, 128);
if ($icon === false) {
return false;
}
$icon->setImageFormat("png32");
- $data = $icon->getImageBlob();
+
+ $clone = clone $icon;
+ $clone->scaleImage(16,0);
+ $favicon->addImage($clone);
+
+ $clone = clone $icon;
+ $clone->scaleImage(32,0);
+ $favicon->addImage($clone);
+
+ $clone = clone $icon;
+ $clone->scaleImage(64,0);
+ $favicon->addImage($clone);
+
+ $clone = clone $icon;
+ $clone->scaleImage(128,0);
+ $favicon->addImage($clone);
+
+ $data = $favicon->getImagesBlob();
+ $favicon->destroy();
$icon->destroy();
+ $clone->destroy();
return $data;
} catch (\ImagickException $e) {
return false;
diff --git a/apps/theming/tests/IconBuilderTest.php b/apps/theming/tests/IconBuilderTest.php
index f25f76a8180..4f5078d4c56 100644
--- a/apps/theming/tests/IconBuilderTest.php
+++ b/apps/theming/tests/IconBuilderTest.php
@@ -71,6 +71,9 @@ class IconBuilderTest extends TestCase {
if (count($checkImagick->queryFormats('SVG')) < 1) {
$this->markTestSkipped('No SVG provider present.');
}
+ if (count($checkImagick->queryFormats('PNG')) < 1) {
+ $this->markTestSkipped('No PNG provider present.');
+ }
}
public function dataRenderAppIcon() {
@@ -147,16 +150,22 @@ class IconBuilderTest extends TestCase {
public function testGetFavicon($app, $color, $file) {
$this->checkImagick();
$this->themingDefaults->expects($this->once())
+ ->method('shouldReplaceIcons')
+ ->willReturn(true);
+ $this->themingDefaults->expects($this->once())
->method('getColorPrimary')
->willReturn($color);
$expectedIcon = new \Imagick(realpath(dirname(__FILE__)). "/data/" . $file);
+ $actualIcon = $this->iconBuilder->getFavicon($app);
+
$icon = new \Imagick();
- $icon->readImageBlob($this->iconBuilder->getFavicon($app));
+ $icon->setFormat('ico');
+ $icon->readImageBlob($actualIcon);
$this->assertEquals(true, $icon->valid());
- $this->assertEquals(32, $icon->getImageWidth());
- $this->assertEquals(32, $icon->getImageHeight());
+ $this->assertEquals(128, $icon->getImageWidth());
+ $this->assertEquals(128, $icon->getImageHeight());
$icon->destroy();
$expectedIcon->destroy();
// FIXME: We may need some comparison of the generated and the test images
@@ -167,8 +176,12 @@ class IconBuilderTest extends TestCase {
* @expectedException \PHPUnit_Framework_Error_Warning
*/
public function testGetFaviconNotFound() {
+ $this->checkImagick();
$util = $this->getMockBuilder(Util::class)->disableOriginalConstructor()->getMock();
$iconBuilder = new IconBuilder($this->themingDefaults, $util);
+ $this->themingDefaults->expects($this->once())
+ ->method('shouldReplaceIcons')
+ ->willReturn(true);
$util->expects($this->once())
->method('getAppIcon')
->willReturn('notexistingfile');
@@ -179,6 +192,7 @@ class IconBuilderTest extends TestCase {
* @expectedException \PHPUnit_Framework_Error_Warning
*/
public function testGetTouchIconNotFound() {
+ $this->checkImagick();
$util = $this->getMockBuilder(Util::class)->disableOriginalConstructor()->getMock();
$iconBuilder = new IconBuilder($this->themingDefaults, $util);
$util->expects($this->once())
@@ -191,6 +205,7 @@ class IconBuilderTest extends TestCase {
* @expectedException \PHPUnit_Framework_Error_Warning
*/
public function testColorSvgNotFound() {
+ $this->checkImagick();
$util = $this->getMockBuilder(Util::class)->disableOriginalConstructor()->getMock();
$iconBuilder = new IconBuilder($this->themingDefaults, $util);
$util->expects($this->once())
diff --git a/apps/user_ldap/js/wizard/wizardTabElementary.js b/apps/user_ldap/js/wizard/wizardTabElementary.js
index 7ce1009565d..3c6eb1adc45 100644
--- a/apps/user_ldap/js/wizard/wizardTabElementary.js
+++ b/apps/user_ldap/js/wizard/wizardTabElementary.js
@@ -214,6 +214,7 @@ OCA = OCA || {};
onConfigSwitch: function(view, configuration) {
this.baseDNTestTriggered = false;
view.disableElement(view.managedItems.ldap_port.$relatedElements);
+ view.managedItems.ldap_dn.$saveButton.removeClass('primary');
view.onConfigLoaded(view, configuration);
},
diff --git a/apps/user_ldap/js/wizard/wizardTabGeneric.js b/apps/user_ldap/js/wizard/wizardTabGeneric.js
index 57ac375e321..9997d6e1b04 100644
--- a/apps/user_ldap/js/wizard/wizardTabGeneric.js
+++ b/apps/user_ldap/js/wizard/wizardTabGeneric.js
@@ -359,6 +359,10 @@ OCA = OCA || {};
item.$saveButton.click(function(event) {
event.preventDefault();
view._requestSave(item.$element);
+ item.$saveButton.removeClass('primary');
+ });
+ item.$element.change(function () {
+ item.$saveButton.addClass('primary');
});
})(this.managedItems[id]);
}
diff --git a/apps/user_ldap/l10n/es_CL.js b/apps/user_ldap/l10n/es_CL.js
index 63d3d71e0a9..f87d7051878 100644
--- a/apps/user_ldap/l10n/es_CL.js
+++ b/apps/user_ldap/l10n/es_CL.js
@@ -99,6 +99,7 @@ OC.L10N.register(
"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "El DN del cliente del usuario con el que se vinculará, ejem. uid=agente,dc=ejemplo,dc=com. Para tener un acceso anónimo, deja el DN y la contraseña vacíos.",
"Password" : "Contraseña",
"For anonymous access, leave DN and Password empty." : "Para acceso anónimo, deja la contraseña y DN vacíos.",
+ "Save Credentials" : "Guardar credenciales",
"One Base DN per line" : "Un DN Base por línea",
"You can specify Base DN for users and groups in the Advanced tab" : "Puedes especificar el DN Base para usuarios y grupos en la pestaña Avanzado",
"Detect Base DN" : "Detectar DN Base",
diff --git a/apps/user_ldap/l10n/es_CL.json b/apps/user_ldap/l10n/es_CL.json
index eefeb9a037f..d92be60abe0 100644
--- a/apps/user_ldap/l10n/es_CL.json
+++ b/apps/user_ldap/l10n/es_CL.json
@@ -97,6 +97,7 @@
"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "El DN del cliente del usuario con el que se vinculará, ejem. uid=agente,dc=ejemplo,dc=com. Para tener un acceso anónimo, deja el DN y la contraseña vacíos.",
"Password" : "Contraseña",
"For anonymous access, leave DN and Password empty." : "Para acceso anónimo, deja la contraseña y DN vacíos.",
+ "Save Credentials" : "Guardar credenciales",
"One Base DN per line" : "Un DN Base por línea",
"You can specify Base DN for users and groups in the Advanced tab" : "Puedes especificar el DN Base para usuarios y grupos en la pestaña Avanzado",
"Detect Base DN" : "Detectar DN Base",
diff --git a/apps/user_ldap/l10n/ru.js b/apps/user_ldap/l10n/ru.js
index d1d4d0331ea..09e300528e9 100644
--- a/apps/user_ldap/l10n/ru.js
+++ b/apps/user_ldap/l10n/ru.js
@@ -99,6 +99,7 @@ OC.L10N.register(
"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "DN пользователя, под которым выполняется подключение, например, uid=agent,dc=example,dc=com. Для анонимного доступа оставьте DN и пароль пустыми.",
"Password" : "Пароль",
"For anonymous access, leave DN and Password empty." : "Для анонимного доступа оставьте DN и пароль пустыми.",
+ "Save Credentials" : "Сохранить учётные данные",
"One Base DN per line" : "По одной базе поиска (Base DN) в строке.",
"You can specify Base DN for users and groups in the Advanced tab" : "Вы можете задать Base DN для пользователей и групп на вкладке \"Расширенные\"",
"Detect Base DN" : "Определить базу поиска DN",
diff --git a/apps/user_ldap/l10n/ru.json b/apps/user_ldap/l10n/ru.json
index 6ae07d14b68..eb23609a805 100644
--- a/apps/user_ldap/l10n/ru.json
+++ b/apps/user_ldap/l10n/ru.json
@@ -97,6 +97,7 @@
"The DN of the client user with which the bind shall be done, e.g. uid=agent,dc=example,dc=com. For anonymous access, leave DN and Password empty." : "DN пользователя, под которым выполняется подключение, например, uid=agent,dc=example,dc=com. Для анонимного доступа оставьте DN и пароль пустыми.",
"Password" : "Пароль",
"For anonymous access, leave DN and Password empty." : "Для анонимного доступа оставьте DN и пароль пустыми.",
+ "Save Credentials" : "Сохранить учётные данные",
"One Base DN per line" : "По одной базе поиска (Base DN) в строке.",
"You can specify Base DN for users and groups in the Advanced tab" : "Вы можете задать Base DN для пользователей и групп на вкладке \"Расширенные\"",
"Detect Base DN" : "Определить базу поиска DN",
diff --git a/apps/user_ldap/lib/User/User.php b/apps/user_ldap/lib/User/User.php
index afd43999c7f..c93d2a77d80 100644
--- a/apps/user_ldap/lib/User/User.php
+++ b/apps/user_ldap/lib/User/User.php
@@ -387,8 +387,7 @@ class User {
$lastChecked = $this->config->getUserValue($this->uid, 'user_ldap',
self::USER_PREFKEY_LASTREFRESH, 0);
- //TODO make interval configurable
- if((time() - intval($lastChecked)) < 86400 ) {
+ if((time() - intval($lastChecked)) < intval($this->config->getAppValue('user_ldap', 'updateAttributesInterval', 86400)) ) {
return false;
}
return true;
diff --git a/apps/user_ldap/templates/part.wizardcontrols.php b/apps/user_ldap/templates/part.wizardcontrols.php
index 89eb96827e6..bd84b23c76d 100644
--- a/apps/user_ldap/templates/part.wizardcontrols.php
+++ b/apps/user_ldap/templates/part.wizardcontrols.php
@@ -5,7 +5,7 @@
type="button">
<?php p($l->t('Back'));?>
</button>
- <button class="ldap_action_continue" name="ldap_action_continue" type="button">
+ <button class="ldap_action_continue primary" name="ldap_action_continue" type="button">
<?php p($l->t('Continue'));?>
</button>
<a href="<?php p(link_to_docs('admin-ldap')); ?>"
diff --git a/apps/user_ldap/tests/User/UserTest.php b/apps/user_ldap/tests/User/UserTest.php
index 5e911159285..27bd7762e39 100644
--- a/apps/user_ldap/tests/User/UserTest.php
+++ b/apps/user_ldap/tests/User/UserTest.php
@@ -871,7 +871,14 @@ class UserTest extends \Test\TestCase {
->with($this->equalTo('alice'), $this->equalTo('user_ldap'),
$this->equalTo(User::USER_PREFKEY_LASTREFRESH),
$this->equalTo(0))
- ->will($this->returnValue(time()));
+ ->will($this->returnValue(time() - 10));
+
+ $config->expects($this->once())
+ ->method('getAppValue')
+ ->with($this->equalTo('user_ldap'),
+ $this->equalTo('updateAttributesInterval'),
+ $this->anything())
+ ->will($this->returnValue(1800));
$config->expects($this->exactly(2))
->method('getUserValue');
$config->expects($this->never())