js.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020
  1. /**
  2. * Disable console output unless DEBUG mode is enabled.
  3. * Add
  4. * define('DEBUG', true);
  5. * To the end of config/config.php to enable debug mode.
  6. * The undefined checks fix the broken ie8 console
  7. */
  8. var oc_debug;
  9. var oc_webroot;
  10. var oc_current_user = document.getElementsByTagName('head')[0].getAttribute('data-user');
  11. var oc_requesttoken = document.getElementsByTagName('head')[0].getAttribute('data-requesttoken');
  12. window.oc_config = window.oc_config || {};
  13. if (typeof oc_webroot === "undefined") {
  14. oc_webroot = location.pathname;
  15. var pos = oc_webroot.indexOf('/index.php/');
  16. if (pos !== -1) {
  17. oc_webroot = oc_webroot.substr(0, pos);
  18. }
  19. else {
  20. oc_webroot = oc_webroot.substr(0, oc_webroot.lastIndexOf('/'));
  21. }
  22. }
  23. if (oc_debug !== true || typeof console === "undefined" || typeof console.log === "undefined") {
  24. if (!window.console) {
  25. window.console = {};
  26. }
  27. var methods = ['log', 'debug', 'warn', 'info', 'error', 'assert'];
  28. for (var i = 0; i < methods.length; i++) {
  29. console[methods[i]] = function () { };
  30. }
  31. }
  32. function initL10N(app) {
  33. if (!( t.cache[app] )) {
  34. $.ajax(OC.filePath('core', 'ajax', 'translations.php'), {
  35. async: false,//todo a proper solution for this without sync ajax calls
  36. data: {'app': app},
  37. type: 'POST',
  38. success: function (jsondata) {
  39. t.cache[app] = jsondata.data;
  40. t.plural_form = jsondata.plural_form;
  41. }
  42. });
  43. // Bad answer ...
  44. if (!( t.cache[app] )) {
  45. t.cache[app] = [];
  46. }
  47. }
  48. if (typeof t.plural_function[app] == 'undefined') {
  49. t.plural_function[app] = function (n) {
  50. var p = (n != 1) ? 1 : 0;
  51. return { 'nplural' : 2, 'plural' : p };
  52. };
  53. /**
  54. * code below has been taken from jsgettext - which is LGPL licensed
  55. * https://developer.berlios.de/projects/jsgettext/
  56. * http://cvs.berlios.de/cgi-bin/viewcvs.cgi/jsgettext/jsgettext/lib/Gettext.js
  57. */
  58. var pf_re = new RegExp('^(\\s*nplurals\\s*=\\s*[0-9]+\\s*;\\s*plural\\s*=\\s*(?:\\s|[-\\?\\|&=!<>+*/%:;a-zA-Z0-9_\(\)])+)', 'm');
  59. if (pf_re.test(t.plural_form)) {
  60. //ex english: "Plural-Forms: nplurals=2; plural=(n != 1);\n"
  61. //pf = "nplurals=2; plural=(n != 1);";
  62. //ex russian: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10< =4 && (n%100<10 or n%100>=20) ? 1 : 2)
  63. //pf = "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)";
  64. var pf = t.plural_form;
  65. if (! /;\s*$/.test(pf)) pf = pf.concat(';');
  66. /* We used to use eval, but it seems IE has issues with it.
  67. * We now use "new Function", though it carries a slightly
  68. * bigger performance hit.
  69. var code = 'function (n) { var plural; var nplurals; '+pf+' return { "nplural" : nplurals, "plural" : (plural === true ? 1 : plural ? plural : 0) }; };';
  70. Gettext._locale_data[domain].head.plural_func = eval("("+code+")");
  71. */
  72. var code = 'var plural; var nplurals; '+pf+' return { "nplural" : nplurals, "plural" : (plural === true ? 1 : plural ? plural : 0) };';
  73. t.plural_function[app] = new Function("n", code);
  74. } else {
  75. console.log("Syntax error in language file. Plural-Forms header is invalid ["+t.plural_forms+"]");
  76. }
  77. }
  78. }
  79. /**
  80. * translate a string
  81. * @param app the id of the app for which to translate the string
  82. * @param text the string to translate
  83. * @param vars (optional) FIXME
  84. * @param count (optional) number to replace %n with
  85. * @return string
  86. */
  87. function t(app, text, vars, count){
  88. initL10N(app);
  89. var _build = function (text, vars, count) {
  90. return text.replace(/%n/g, count).replace(/{([^{}]*)}/g,
  91. function (a, b) {
  92. var r = vars[b];
  93. return typeof r === 'string' || typeof r === 'number' ? r : a;
  94. }
  95. );
  96. };
  97. var translation = text;
  98. if( typeof( t.cache[app][text] ) !== 'undefined' ){
  99. translation = t.cache[app][text];
  100. }
  101. if(typeof vars === 'object' || count !== undefined ) {
  102. return _build(translation, vars, count);
  103. } else {
  104. return translation;
  105. }
  106. }
  107. t.cache = {};
  108. // different apps might or might not redefine the nplurals function correctly
  109. // this is to make sure that a "broken" app doesn't mess up with the
  110. // other app's plural function
  111. t.plural_function = {};
  112. /**
  113. * translate a string
  114. * @param app the id of the app for which to translate the string
  115. * @param text_singular the string to translate for exactly one object
  116. * @param text_plural the string to translate for n objects
  117. * @param count number to determine whether to use singular or plural
  118. * @param vars (optional) FIXME
  119. * @return string
  120. */
  121. function n(app, text_singular, text_plural, count, vars) {
  122. initL10N(app);
  123. var identifier = '_' + text_singular + '_::_' + text_plural + '_';
  124. if( typeof( t.cache[app][identifier] ) !== 'undefined' ){
  125. var translation = t.cache[app][identifier];
  126. if ($.isArray(translation)) {
  127. var plural = t.plural_function[app](count);
  128. return t(app, translation[plural.plural], vars, count);
  129. }
  130. }
  131. if(count === 1) {
  132. return t(app, text_singular, vars, count);
  133. }
  134. else{
  135. return t(app, text_plural, vars, count);
  136. }
  137. }
  138. /**
  139. * Sanitizes a HTML string
  140. * @param s string
  141. * @return Sanitized string
  142. */
  143. function escapeHTML(s) {
  144. return s.toString().split('&').join('&amp;').split('<').join('&lt;').split('"').join('&quot;');
  145. }
  146. /**
  147. * Get the path to download a file
  148. * @param file The filename
  149. * @param dir The directory the file is in - e.g. $('#dir').val()
  150. * @return string
  151. */
  152. function fileDownloadPath(dir, file) {
  153. return OC.filePath('files', 'ajax', 'download.php')+'?files='+encodeURIComponent(file)+'&dir='+encodeURIComponent(dir);
  154. }
  155. var OC={
  156. PERMISSION_CREATE:4,
  157. PERMISSION_READ:1,
  158. PERMISSION_UPDATE:2,
  159. PERMISSION_DELETE:8,
  160. PERMISSION_SHARE:16,
  161. PERMISSION_ALL:31,
  162. webroot:oc_webroot,
  163. appswebroots:(typeof oc_appswebroots !== 'undefined') ? oc_appswebroots:false,
  164. currentUser:(typeof oc_current_user!=='undefined')?oc_current_user:false,
  165. coreApps:['', 'admin','log','search','settings','core','3rdparty'],
  166. /**
  167. * get an absolute url to a file in an appen
  168. * @param app the id of the app the file belongs to
  169. * @param file the file path relative to the app folder
  170. * @return string
  171. */
  172. linkTo:function(app,file){
  173. return OC.filePath(app,'',file);
  174. },
  175. /**
  176. * Creates an url for remote use
  177. * @param string $service id
  178. * @return string the url
  179. *
  180. * Returns a url to the given service.
  181. */
  182. linkToRemoteBase:function(service) {
  183. return OC.webroot + '/remote.php/' + service;
  184. },
  185. /**
  186. * @brief Creates an absolute url for remote use
  187. * @param string $service id
  188. * @param bool $add_slash
  189. * @return string the url
  190. *
  191. * Returns a absolute url to the given service.
  192. */
  193. linkToRemote:function(service) {
  194. return window.location.protocol + '//' + window.location.host + OC.linkToRemoteBase(service);
  195. },
  196. /**
  197. * get the absolute url for a file in an app
  198. * @param app the id of the app
  199. * @param type the type of the file to link to (e.g. css,img,ajax.template)
  200. * @param file the filename
  201. * @return string
  202. */
  203. filePath:function(app,type,file){
  204. var isCore=OC.coreApps.indexOf(app)!==-1,
  205. link=OC.webroot;
  206. if((file.substring(file.length-3) === 'php' || file.substring(file.length-3) === 'css') && !isCore){
  207. link+='/index.php/apps/' + app;
  208. if (file != 'index.php') {
  209. link+='/';
  210. if(type){
  211. link+=encodeURI(type + '/');
  212. }
  213. link+= file;
  214. }
  215. }else if(file.substring(file.length-3) !== 'php' && !isCore){
  216. link=OC.appswebroots[app];
  217. if(type){
  218. link+= '/'+type+'/';
  219. }
  220. if(link.substring(link.length-1) !== '/'){
  221. link+='/';
  222. }
  223. link+=file;
  224. }else{
  225. if ((app == 'settings' || app == 'core' || app == 'search') && type == 'ajax') {
  226. link+='/index.php/';
  227. }
  228. else {
  229. link+='/';
  230. }
  231. if(!isCore){
  232. link+='apps/';
  233. }
  234. if (app !== '') {
  235. app+='/';
  236. link+=app;
  237. }
  238. if(type){
  239. link+=type+'/';
  240. }
  241. link+=file;
  242. }
  243. return link;
  244. },
  245. /**
  246. * Redirect to the target URL, can also be used for downloads.
  247. */
  248. redirect: function(targetUrl) {
  249. window.location = targetUrl;
  250. },
  251. /**
  252. * get the absolute path to an image file
  253. * @param app the app id to which the image belongs
  254. * @param file the name of the image file
  255. * @return string
  256. *
  257. * if no extension is given for the image, it will automatically decide between .png and .svg based on what the browser supports
  258. */
  259. imagePath:function(app,file){
  260. if(file.indexOf('.')==-1){//if no extension is given, use png or svg depending on browser support
  261. file+=(SVGSupport())?'.svg':'.png';
  262. }
  263. return OC.filePath(app,'img',file);
  264. },
  265. /**
  266. * load a script for the server and load it
  267. * @param app the app id to which the script belongs
  268. * @param script the filename of the script
  269. * @param ready event handeler to be called when the script is loaded
  270. *
  271. * if the script is already loaded, the event handeler will be called directly
  272. */
  273. addScript:function(app,script,ready){
  274. var deferred, path=OC.filePath(app,'js',script+'.js');
  275. if(!OC.addScript.loaded[path]){
  276. if(ready){
  277. deferred=$.getScript(path,ready);
  278. }else{
  279. deferred=$.getScript(path);
  280. }
  281. OC.addScript.loaded[path]=deferred;
  282. }else{
  283. if(ready){
  284. ready();
  285. }
  286. }
  287. return OC.addScript.loaded[path];
  288. },
  289. /**
  290. * load a css file and load it
  291. * @param app the app id to which the css style belongs
  292. * @param style the filename of the css file
  293. */
  294. addStyle:function(app,style){
  295. var path=OC.filePath(app,'css',style+'.css');
  296. if(OC.addStyle.loaded.indexOf(path)===-1){
  297. OC.addStyle.loaded.push(path);
  298. if (document.createStyleSheet) {
  299. document.createStyleSheet(path);
  300. } else {
  301. style=$('<link rel="stylesheet" type="text/css" href="'+path+'"/>');
  302. $('head').append(style);
  303. }
  304. }
  305. },
  306. basename: function(path) {
  307. return path.replace(/\\/g,'/').replace( /.*\//, '' );
  308. },
  309. dirname: function(path) {
  310. return path.replace(/\\/g,'/').replace(/\/[^\/]*$/, '');
  311. },
  312. /**
  313. * do a search query and display the results
  314. * @param query the search query
  315. */
  316. search:function(query){
  317. if(query){
  318. OC.addStyle('search','results');
  319. $.getJSON(OC.filePath('search','ajax','search.php')+'?query='+encodeURIComponent(query), function(results){
  320. OC.search.lastResults=results;
  321. OC.search.showResults(results);
  322. });
  323. }
  324. },
  325. dialogs:OCdialogs,
  326. mtime2date:function(mtime) {
  327. mtime = parseInt(mtime,10);
  328. var date = new Date(1000*mtime);
  329. return date.getDate()+'.'+(date.getMonth()+1)+'.'+date.getFullYear()+', '+date.getHours()+':'+date.getMinutes();
  330. },
  331. /**
  332. * Parses a URL query string into a JS map
  333. * @param queryString query string in the format param1=1234&param2=abcde&param3=xyz
  334. * @return map containing key/values matching the URL parameters
  335. */
  336. parseQueryString:function(queryString){
  337. var parts,
  338. components,
  339. result = {},
  340. key,
  341. value;
  342. if (!queryString){
  343. return null;
  344. }
  345. if (queryString[0] === '?'){
  346. queryString = queryString.substr(1);
  347. }
  348. parts = queryString.split('&');
  349. for (var i = 0; i < parts.length; i++){
  350. components = parts[i].split('=');
  351. if (!components.length){
  352. continue;
  353. }
  354. key = decodeURIComponent(components[0]);
  355. if (!key){
  356. continue;
  357. }
  358. value = components[1];
  359. result[key] = value && decodeURIComponent(value);
  360. }
  361. return result;
  362. },
  363. /**
  364. * Builds a URL query from a JS map.
  365. * @param params parameter map
  366. * @return string containing a URL query (without question) mark
  367. */
  368. buildQueryString: function(params) {
  369. var s = '';
  370. var first = true;
  371. if (!params) {
  372. return s;
  373. }
  374. for (var key in params) {
  375. var value = params[key];
  376. if (first) {
  377. first = false;
  378. }
  379. else {
  380. s += '&';
  381. }
  382. s += encodeURIComponent(key);
  383. if (value !== null && typeof(value) !== 'undefined') {
  384. s += '=' + encodeURIComponent(value);
  385. }
  386. }
  387. return s;
  388. },
  389. /**
  390. * Opens a popup with the setting for an app.
  391. * @param appid String. The ID of the app e.g. 'calendar', 'contacts' or 'files'.
  392. * @param loadJS boolean or String. If true 'js/settings.js' is loaded. If it's a string
  393. * it will attempt to load a script by that name in the 'js' directory.
  394. * @param cache boolean. If true the javascript file won't be forced refreshed. Defaults to true.
  395. * @param scriptName String. The name of the PHP file to load. Defaults to 'settings.php' in
  396. * the root of the app directory hierarchy.
  397. */
  398. appSettings:function(args) {
  399. if(typeof args === 'undefined' || typeof args.appid === 'undefined') {
  400. throw { name: 'MissingParameter', message: 'The parameter appid is missing' };
  401. }
  402. var props = {scriptName:'settings.php', cache:true};
  403. $.extend(props, args);
  404. var settings = $('#appsettings');
  405. if(settings.length == 0) {
  406. throw { name: 'MissingDOMElement', message: 'There has be be an element with id "appsettings" for the popup to show.' };
  407. }
  408. var popup = $('#appsettings_popup');
  409. if(popup.length == 0) {
  410. $('body').prepend('<div class="popup hidden" id="appsettings_popup"></div>');
  411. popup = $('#appsettings_popup');
  412. popup.addClass(settings.hasClass('topright') ? 'topright' : 'bottomleft');
  413. }
  414. if(popup.is(':visible')) {
  415. popup.hide().remove();
  416. } else {
  417. var arrowclass = settings.hasClass('topright') ? 'up' : 'left';
  418. var jqxhr = $.get(OC.filePath(props.appid, '', props.scriptName), function(data) {
  419. popup.html(data).ready(function() {
  420. popup.prepend('<span class="arrow '+arrowclass+'"></span><h2>'+t('core', 'Settings')+'</h2><a class="close svg"></a>').show();
  421. popup.find('.close').bind('click', function() {
  422. popup.remove();
  423. });
  424. if(typeof props.loadJS !== 'undefined') {
  425. var scriptname;
  426. if(props.loadJS === true) {
  427. scriptname = 'settings.js';
  428. } else if(typeof props.loadJS === 'string') {
  429. scriptname = props.loadJS;
  430. } else {
  431. throw { name: 'InvalidParameter', message: 'The "loadJS" parameter must be either boolean or a string.' };
  432. }
  433. if(props.cache) {
  434. $.ajaxSetup({cache: true});
  435. }
  436. $.getScript(OC.filePath(props.appid, 'js', scriptname))
  437. .fail(function(jqxhr, settings, e) {
  438. throw e;
  439. });
  440. }
  441. if(!SVGSupport()) {
  442. replaceSVG();
  443. }
  444. }).show();
  445. }, 'html');
  446. }
  447. }
  448. };
  449. OC.search.customResults={};
  450. OC.search.currentResult=-1;
  451. OC.search.lastQuery='';
  452. OC.search.lastResults={};
  453. OC.addStyle.loaded=[];
  454. OC.addScript.loaded=[];
  455. OC.Notification={
  456. queuedNotifications: [],
  457. getDefaultNotificationFunction: null,
  458. setDefault: function(callback) {
  459. OC.Notification.getDefaultNotificationFunction = callback;
  460. },
  461. hide: function(callback) {
  462. $('#notification').fadeOut('400', function(){
  463. if (OC.Notification.isHidden()) {
  464. if (OC.Notification.getDefaultNotificationFunction) {
  465. OC.Notification.getDefaultNotificationFunction.call();
  466. }
  467. }
  468. if (callback) {
  469. callback.call();
  470. }
  471. $('#notification').empty();
  472. if(OC.Notification.queuedNotifications.length > 0){
  473. OC.Notification.showHtml(OC.Notification.queuedNotifications[0]);
  474. OC.Notification.queuedNotifications.shift();
  475. }
  476. });
  477. },
  478. showHtml: function(html) {
  479. if(($('#notification').filter('span.undo').length == 1) || OC.Notification.isHidden()){
  480. $('#notification').html(html);
  481. $('#notification').fadeIn().css("display","inline");
  482. }else{
  483. OC.Notification.queuedNotifications.push(html);
  484. }
  485. },
  486. show: function(text) {
  487. if(($('#notification').filter('span.undo').length == 1) || OC.Notification.isHidden()){
  488. $('#notification').text(text);
  489. $('#notification').fadeIn().css("display","inline");
  490. }else{
  491. OC.Notification.queuedNotifications.push($('<div/>').text(text).html());
  492. }
  493. },
  494. isHidden: function() {
  495. return ($("#notification").text() === '');
  496. }
  497. };
  498. OC.Breadcrumb={
  499. container:null,
  500. show:function(dir, leafname, leaflink){
  501. if(!this.container){//default
  502. this.container=$('#controls');
  503. }
  504. this._show(this.container, dir, leafname, leaflink);
  505. },
  506. _show:function(container, dir, leafname, leaflink){
  507. var self = this;
  508. this._clear(container);
  509. // show home + path in subdirectories
  510. if (dir) {
  511. //add home
  512. var link = OC.linkTo('files','index.php');
  513. var crumb=$('<div/>');
  514. crumb.addClass('crumb');
  515. var crumbLink=$('<a/>');
  516. crumbLink.attr('href',link);
  517. var crumbImg=$('<img/>');
  518. crumbImg.attr('src',OC.imagePath('core','places/home'));
  519. crumbLink.append(crumbImg);
  520. crumb.append(crumbLink);
  521. container.prepend(crumb);
  522. //add path parts
  523. var segments = dir.split('/');
  524. var pathurl = '';
  525. jQuery.each(segments, function(i,name) {
  526. if (name !== '') {
  527. pathurl = pathurl+'/'+name;
  528. var link = OC.linkTo('files','index.php')+'?dir='+encodeURIComponent(pathurl);
  529. self._push(container, name, link);
  530. }
  531. });
  532. }
  533. //add leafname
  534. if (leafname && leaflink) {
  535. this._push(container, leafname, leaflink);
  536. }
  537. },
  538. push:function(name, link){
  539. if(!this.container){//default
  540. this.container=$('#controls');
  541. }
  542. return this._push(OC.Breadcrumb.container, name, link);
  543. },
  544. _push:function(container, name, link){
  545. var crumb=$('<div/>');
  546. crumb.addClass('crumb').addClass('last');
  547. var crumbLink=$('<a/>');
  548. crumbLink.attr('href',link);
  549. crumbLink.text(name);
  550. crumb.append(crumbLink);
  551. var existing=container.find('div.crumb');
  552. if(existing.length){
  553. existing.removeClass('last');
  554. existing.last().after(crumb);
  555. }else{
  556. container.prepend(crumb);
  557. }
  558. return crumb;
  559. },
  560. pop:function(){
  561. if(!this.container){//default
  562. this.container=$('#controls');
  563. }
  564. this.container.find('div.crumb').last().remove();
  565. this.container.find('div.crumb').last().addClass('last');
  566. },
  567. clear:function(){
  568. if(!this.container){//default
  569. this.container=$('#controls');
  570. }
  571. this._clear(this.container);
  572. },
  573. _clear:function(container) {
  574. container.find('div.crumb').remove();
  575. }
  576. };
  577. if(typeof localStorage !=='undefined' && localStorage !== null){
  578. //user and instance aware localstorage
  579. OC.localStorage={
  580. namespace:'oc_'+OC.currentUser+'_'+OC.webroot+'_',
  581. hasItem:function(name){
  582. return OC.localStorage.getItem(name)!==null;
  583. },
  584. setItem:function(name,item){
  585. return localStorage.setItem(OC.localStorage.namespace+name,JSON.stringify(item));
  586. },
  587. getItem:function(name){
  588. var item = localStorage.getItem(OC.localStorage.namespace+name);
  589. if(item===null) {
  590. return null;
  591. } else if (typeof JSON === 'undefined') {
  592. //fallback to jquery for IE6/7/8
  593. return $.parseJSON(item);
  594. } else {
  595. return JSON.parse(item);
  596. }
  597. }
  598. };
  599. }else{
  600. //dummy localstorage
  601. OC.localStorage={
  602. hasItem:function(){
  603. return false;
  604. },
  605. setItem:function(){
  606. return false;
  607. },
  608. getItem:function(){
  609. return null;
  610. }
  611. };
  612. }
  613. /**
  614. * check if the browser support svg images
  615. */
  616. function SVGSupport() {
  617. return SVGSupport.checkMimeType.correct && !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', "svg").createSVGRect;
  618. }
  619. SVGSupport.checkMimeType=function(){
  620. $.ajax({
  621. url: OC.imagePath('core','breadcrumb.svg'),
  622. success:function(data,text,xhr){
  623. var headerParts=xhr.getAllResponseHeaders().split("\n");
  624. var headers={};
  625. $.each(headerParts,function(i,text){
  626. if(text){
  627. var parts=text.split(':',2);
  628. if(parts.length===2){
  629. var value=parts[1].trim();
  630. if(value[0]==='"'){
  631. value=value.substr(1,value.length-2);
  632. }
  633. headers[parts[0]]=value;
  634. }
  635. }
  636. });
  637. if(headers["Content-Type"]!=='image/svg+xml'){
  638. replaceSVG();
  639. SVGSupport.checkMimeType.correct=false;
  640. }
  641. }
  642. });
  643. };
  644. SVGSupport.checkMimeType.correct=true;
  645. //replace all svg images with png for browser compatibility
  646. function replaceSVG(){
  647. $('img.svg').each(function(index,element){
  648. element=$(element);
  649. var src=element.attr('src');
  650. element.attr('src',src.substr(0,src.length-3)+'png');
  651. });
  652. $('.svg').each(function(index,element){
  653. element=$(element);
  654. var background=element.css('background-image');
  655. if(background){
  656. var i=background.lastIndexOf('.svg');
  657. if(i>=0){
  658. background=background.substr(0,i)+'.png'+background.substr(i+4);
  659. element.css('background-image',background);
  660. }
  661. }
  662. element.find('*').each(function(index,element) {
  663. element=$(element);
  664. var background=element.css('background-image');
  665. if(background){
  666. var i=background.lastIndexOf('.svg');
  667. if(i>=0){
  668. background=background.substr(0,i)+'.png'+background.substr(i+4);
  669. element.css('background-image',background);
  670. }
  671. }
  672. });
  673. });
  674. }
  675. /**
  676. * prototypal inharitence functions
  677. *
  678. * usage:
  679. * MySubObject=object(MyObject)
  680. */
  681. function object(o) {
  682. function F() {}
  683. F.prototype = o;
  684. return new F();
  685. }
  686. /**
  687. * Fills height of window. (more precise than height: 100%;)
  688. */
  689. function fillHeight(selector) {
  690. if (selector.length === 0) {
  691. return;
  692. }
  693. var height = parseFloat($(window).height())-selector.offset().top;
  694. selector.css('height', height + 'px');
  695. if(selector.outerHeight() > selector.height()){
  696. selector.css('height', height-(selector.outerHeight()-selector.height()) + 'px');
  697. }
  698. console.warn("This function is deprecated! Use CSS instead");
  699. }
  700. /**
  701. * Fills height and width of window. (more precise than height: 100%; or width: 100%;)
  702. */
  703. function fillWindow(selector) {
  704. if (selector.length === 0) {
  705. return;
  706. }
  707. fillHeight(selector);
  708. var width = parseFloat($(window).width())-selector.offset().left;
  709. selector.css('width', width + 'px');
  710. if(selector.outerWidth() > selector.width()){
  711. selector.css('width', width-(selector.outerWidth()-selector.width()) + 'px');
  712. }
  713. console.warn("This function is deprecated! Use CSS instead");
  714. }
  715. /**
  716. * Initializes core
  717. */
  718. function initCore() {
  719. /**
  720. * Calls the server periodically to ensure that session doesn't
  721. * time out
  722. */
  723. function initSessionHeartBeat(){
  724. // interval in seconds
  725. var interval = 900;
  726. if (oc_config.session_lifetime) {
  727. interval = Math.floor(oc_config.session_lifetime / 2);
  728. }
  729. // minimum one minute
  730. if (interval < 60) {
  731. interval = 60;
  732. }
  733. OC.Router.registerLoadedCallback(function(){
  734. var url = OC.Router.generate('heartbeat');
  735. setInterval(function(){
  736. $.post(url);
  737. }, interval * 1000);
  738. });
  739. }
  740. // session heartbeat (defaults to enabled)
  741. if (typeof(oc_config.session_keepalive) === 'undefined' ||
  742. !!oc_config.session_keepalive) {
  743. initSessionHeartBeat();
  744. }
  745. if(!SVGSupport()){ //replace all svg images with png images for browser that dont support svg
  746. replaceSVG();
  747. }else{
  748. SVGSupport.checkMimeType();
  749. }
  750. $('form.searchbox').submit(function(event){
  751. event.preventDefault();
  752. });
  753. $('#searchbox').keyup(function(event){
  754. if(event.keyCode===13){//enter
  755. if(OC.search.currentResult>-1){
  756. var result=$('#searchresults tr.result a')[OC.search.currentResult];
  757. window.location = $(result).attr('href');
  758. }
  759. }else if(event.keyCode===38){//up
  760. if(OC.search.currentResult>0){
  761. OC.search.currentResult--;
  762. OC.search.renderCurrent();
  763. }
  764. }else if(event.keyCode===40){//down
  765. if(OC.search.lastResults.length>OC.search.currentResult+1){
  766. OC.search.currentResult++;
  767. OC.search.renderCurrent();
  768. }
  769. }else if(event.keyCode===27){//esc
  770. OC.search.hide();
  771. if (FileList && typeof FileList.unfilter === 'function') { //TODO add hook system
  772. FileList.unfilter();
  773. }
  774. }else{
  775. var query=$('#searchbox').val();
  776. if(OC.search.lastQuery!==query){
  777. OC.search.lastQuery=query;
  778. OC.search.currentResult=-1;
  779. if (FileList && typeof FileList.filter === 'function') { //TODO add hook system
  780. FileList.filter(query);
  781. }
  782. if(query.length>2){
  783. OC.search(query);
  784. }else{
  785. if(OC.search.hide){
  786. OC.search.hide();
  787. }
  788. }
  789. }
  790. }
  791. });
  792. var setShowPassword = function(input, label) {
  793. input.showPassword().keyup();
  794. };
  795. setShowPassword($('#adminpass'), $('label[for=show]'));
  796. setShowPassword($('#pass2'), $('label[for=personal-show]'));
  797. setShowPassword($('#dbpass'), $('label[for=dbpassword]'));
  798. //use infield labels
  799. $("label.infield").inFieldLabels({
  800. pollDuration: 100
  801. });
  802. var checkShowCredentials = function() {
  803. var empty = false;
  804. $('input#user, input#password').each(function() {
  805. if ($(this).val() === '') {
  806. empty = true;
  807. }
  808. });
  809. if(empty) {
  810. $('#submit').fadeOut();
  811. $('#remember_login').hide();
  812. $('#remember_login+label').fadeOut();
  813. } else {
  814. $('#submit').fadeIn();
  815. $('#remember_login').show();
  816. $('#remember_login+label').fadeIn();
  817. }
  818. };
  819. // hide log in button etc. when form fields not filled
  820. // commented out due to some browsers having issues with it
  821. // checkShowCredentials();
  822. // $('input#user, input#password').keyup(checkShowCredentials);
  823. $('#settings #expand').keydown(function(event) {
  824. if (event.which === 13 || event.which === 32) {
  825. $('#expand').click()
  826. }
  827. });
  828. $('#settings #expand').click(function(event) {
  829. $('#settings #expanddiv').slideToggle(200);
  830. event.stopPropagation();
  831. });
  832. $('#settings #expanddiv').click(function(event){
  833. event.stopPropagation();
  834. });
  835. $(document).click(function(){//hide the settings menu when clicking outside it
  836. $('#settings #expanddiv').slideUp(200);
  837. });
  838. // all the tipsy stuff needs to be here (in reverse order) to work
  839. $('.displayName .action').tipsy({gravity:'se', fade:true, live:true});
  840. $('.password .action').tipsy({gravity:'se', fade:true, live:true});
  841. $('#upload').tipsy({gravity:'w', fade:true});
  842. $('.selectedActions a').tipsy({gravity:'s', fade:true, live:true});
  843. $('a.action.delete').tipsy({gravity:'e', fade:true, live:true});
  844. $('a.action').tipsy({gravity:'s', fade:true, live:true});
  845. $('td .modified').tipsy({gravity:'s', fade:true, live:true});
  846. $('input').tipsy({gravity:'w', fade:true});
  847. }
  848. $(document).ready(initCore);
  849. /**
  850. * Filter Jquery selector by attribute value
  851. */
  852. $.fn.filterAttr = function(attr_name, attr_value) {
  853. return this.filter(function() { return $(this).attr(attr_name) === attr_value; });
  854. };
  855. function humanFileSize(size) {
  856. var humanList = ['B', 'kB', 'MB', 'GB', 'TB'];
  857. // Calculate Log with base 1024: size = 1024 ** order
  858. var order = size?Math.floor(Math.log(size) / Math.log(1024)):0;
  859. // Stay in range of the byte sizes that are defined
  860. order = Math.min(humanList.length - 1, order);
  861. var readableFormat = humanList[order];
  862. var relativeSize = (size / Math.pow(1024, order)).toFixed(1);
  863. if(order < 2){
  864. relativeSize = parseFloat(relativeSize).toFixed(0);
  865. }
  866. else if(relativeSize.substr(relativeSize.length-2,2)==='.0'){
  867. relativeSize=relativeSize.substr(0,relativeSize.length-2);
  868. }
  869. return relativeSize + ' ' + readableFormat;
  870. }
  871. function formatDate(date){
  872. if(typeof date=='number'){
  873. date=new Date(date);
  874. }
  875. return $.datepicker.formatDate(datepickerFormatDate, date)+' '+date.getHours()+':'+((date.getMinutes()<10)?'0':'')+date.getMinutes();
  876. }
  877. // taken from http://stackoverflow.com/questions/1403888/get-url-parameter-with-jquery
  878. function getURLParameter(name) {
  879. return decodeURI(
  880. (RegExp(name + '=' + '(.+?)(&|$)').exec(location.search) || [, null])[1]
  881. );
  882. }
  883. /**
  884. * takes an absolute timestamp and return a string with a human-friendly relative date
  885. * @param int a Unix timestamp
  886. */
  887. function relative_modified_date(timestamp) {
  888. var timediff = Math.round((new Date()).getTime() / 1000) - timestamp;
  889. var diffminutes = Math.round(timediff/60);
  890. var diffhours = Math.round(diffminutes/60);
  891. var diffdays = Math.round(diffhours/24);
  892. var diffmonths = Math.round(diffdays/31);
  893. if(timediff < 60) { return t('core','seconds ago'); }
  894. else if(timediff < 3600) { return n('core','%n minute ago', '%n minutes ago', diffminutes); }
  895. else if(timediff < 86400) { return n('core', '%n hour ago', '%n hours ago', diffhours); }
  896. else if(timediff < 86400) { return t('core','today'); }
  897. else if(timediff < 172800) { return t('core','yesterday'); }
  898. else if(timediff < 2678400) { return n('core', '%n day ago', '%n days ago', diffdays); }
  899. else if(timediff < 5184000) { return t('core','last month'); }
  900. else if(timediff < 31556926) { return n('core', '%n month ago', '%n months ago', diffmonths); }
  901. //else if(timediff < 31556926) { return t('core','months ago'); }
  902. else if(timediff < 63113852) { return t('core','last year'); }
  903. else { return t('core','years ago'); }
  904. }
  905. /**
  906. * get a variable by name
  907. * @param string name
  908. */
  909. OC.get=function(name) {
  910. var namespaces = name.split(".");
  911. var tail = namespaces.pop();
  912. var context=window;
  913. for(var i = 0; i < namespaces.length; i++) {
  914. context = context[namespaces[i]];
  915. if(!context){
  916. return false;
  917. }
  918. }
  919. return context[tail];
  920. };
  921. /**
  922. * set a variable by name
  923. * @param string name
  924. * @param mixed value
  925. */
  926. OC.set=function(name, value) {
  927. var namespaces = name.split(".");
  928. var tail = namespaces.pop();
  929. var context=window;
  930. for(var i = 0; i < namespaces.length; i++) {
  931. if(!context[namespaces[i]]){
  932. context[namespaces[i]]={};
  933. }
  934. context = context[namespaces[i]];
  935. }
  936. context[tail]=value;
  937. };
  938. /**
  939. * select a range in an input field
  940. * @link http://stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area
  941. * @param {type} start
  942. * @param {type} end
  943. */
  944. jQuery.fn.selectRange = function(start, end) {
  945. return this.each(function() {
  946. if (this.setSelectionRange) {
  947. this.focus();
  948. this.setSelectionRange(start, end);
  949. } else if (this.createTextRange) {
  950. var range = this.createTextRange();
  951. range.collapse(true);
  952. range.moveEnd('character', end);
  953. range.moveStart('character', start);
  954. range.select();
  955. }
  956. });
  957. };
  958. /**
  959. * check if an element exists.
  960. * allows you to write if ($('#myid').exists()) to increase readability
  961. * @link http://stackoverflow.com/questions/31044/is-there-an-exists-function-for-jquery
  962. */
  963. jQuery.fn.exists = function(){
  964. return this.length > 0;
  965. };