Advertisement
Guest User

Untitled

a guest
Jan 21st, 2019
362
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 155.81 KB | None | 0 0
  1. //A JSON object that contains the string translations retrieved according to the user's language setting.
  2. var languageFile = {};
  3. //A JSON object that contains the string translations for the default language file (assumed to be English).
  4. var defaultLanguageFile = {};
  5. // convert-readme.txt file with license informations
  6. var convertReadmeFile = "";
  7. //The number of asynchronous calls that have returned from a given batch of calls.
  8. var returnedCalls = 0;
  9. //The number of asynchronous calls that are expected to be made for a given batch of calls.
  10. var expectedCalls = 0;
  11. // Reload side after overlay dialog has been closed
  12. var setReloadSide = false;
  13. // detect safari browser
  14. var browser = "other";
  15. // detect Mac OS
  16. var os = "other";
  17.  
  18. //The currently selected left navigation item.
  19. var activeNav;
  20. //A boolean indicating whether or not the user has made any changes to a page of configuration settings.
  21. var changesMade = false;
  22. //A boolean indicating whether or not the user has clicked an input field
  23. var inputFieldClicked = false;
  24. //The handler to be called if the user elects to save the changes he made.
  25. var saveHandler;
  26.  
  27. //An object containing all the data for the Status page.
  28. var statusData = {};
  29. var statusDataOrig = {};
  30. //The timer that automatically updates the a page at a regular increment.
  31. var updateTimer;
  32. //The interval at which to run the update timer, in milliseconds.
  33. var updateTimerInterval = 30000;
  34. // the status page is updated every 10 seconds 3 times. Then the timer is set to updateTimerInterval.
  35. var updateTimerInterval1 = 2000;
  36. var updateTimerInterval1Count = 0;
  37. // The timer that is initiated after pressing the log in or register button to the myTwonky portal
  38. var portalTimer;
  39. //The interval at which to run the portal timer, in milliseconds.
  40. //This variable gets the values of portalTimerInterval 1, then 2 and 3.
  41. var portalTimerInterval;
  42. // Counts how many times the timer was called. The value 0 indicates that no timer is started.
  43. var portalTimerIntervalCount = 0;
  44. // First (initial) timer interval and how many times he is called
  45. var portalTimerInterval1 = 40000;
  46. var portalTimerInterval1Count = 1;
  47. // Second timer interval and how many times he is called. The value must be different to 1 and 3.
  48. var portalTimerInterval2 = 15000;
  49. var portalTimerInterval2Count = 3;
  50. // Third timer interval and how many times he is called. The value must be different to 1 and 2.
  51. var portalTimerInterval3 = 30000;
  52. var portalTimerInterval3Count = 5;
  53. // timer which clear the background spinner after 5 seconds
  54. var loadingGraficActiv;
  55.  
  56. var noMediaFusionServer = false;
  57. var noWebDavServer = false;
  58. var myTwonkyDisabled = false;
  59.  
  60. // 1: browse shared folder, 2: browse sync folder
  61. var folderBrowseDialogMsg = 1;
  62.  
  63. //An object containing all the data for the Setup page.
  64. var setup = {};
  65. var setupOrig = {};
  66. //The user's currently selected navigation type for the defaultview property.
  67. var selectedNavType;
  68. //An object containing all the data for the Sharing page.
  69. var sharing = {};
  70. var sharingOrig = {};
  71. //update receiver list
  72. var sharingReceiverChanged = false;
  73. //An object containing all the data for the Aggregation page.
  74. var aggregation = {};
  75. var aggregationOrig = {};
  76. //A list of aggregation servers the user has made modifications to. Tracked for optimization to avoid
  77. //sending updates to TwonkyServer when data is saved except for servers the user has changed.
  78. var changedServers = {};
  79. //An object containing all the data for the Advanced page.
  80. var advanced = {};
  81. var advancedOrig = {};
  82. //A list of media receivers the user has made modifications to. Tracked for optimization to avoid
  83. //sending updates to TwonkyServer when data is saved except for receivers the user has changed.
  84. var changedReceivers = {};
  85. //The last media id (corresponding to video, music, or photo) the user visited.
  86. var lastMediaId;
  87.  
  88.  
  89. $(window).bind("hashchange", function(e){
  90. $("#leftNavContainer").show();
  91. switch (e.fragment) {
  92. case "":
  93. case "status":
  94. checkChanges("loadStatus();");
  95. populateSettingsNav();
  96. break;
  97. case "setup":
  98. checkChanges("loadSetup();");
  99. populateSettingsNav();
  100. break;
  101. case "sharing":
  102. checkChanges("loadSharing();");
  103. populateSettingsNav();
  104. break;
  105. case "aggregation":
  106. checkChanges("loadAggregation();");
  107. populateSettingsNav();
  108. break;
  109. case "synchronization":
  110. checkChanges("loadSynchronization();");
  111. break;
  112. case "advanced":
  113. checkChanges("loadAdvanced();");
  114. populateSettingsNav();
  115. break;
  116. case "video":
  117. loadMediaBrowse("0$3");
  118. lastMediaId = "0$3";
  119. break;
  120. case "music":
  121. loadMediaBrowse("0$1");
  122. lastMediaId = "0$1";
  123. break;
  124. case "photo":
  125. loadMediaBrowse("0$2");
  126. lastMediaId = "0$2";
  127. break;
  128. case "licenseinfo":
  129. $("#leftNavContainer").hide();
  130. $(".serverSettingsContentWrapper").html(getString("mpeglicense") + "<br /><br />" + getString("copyright") + "<br /><br /><br /><br />" +
  131. convertReadmeFile + "<br /><br />" +
  132. "<BR><BR>License information is provided here: <br /><br /> " +
  133. "<a class='inlineLink' href='http://jquery.org/license/' >http://jquery.org/license/</a> (click on 'MIT License' link)<br /><br />" +
  134. "<a class='inlineLink' href='http://benalman.com/about/license/' >http://benalman.com/about/license/</a> <br />");
  135. break;
  136. default:
  137. var paramPieces = e.fragment.split("&");
  138. var id = paramPieces[0].split("=")[1];
  139. var startPage = paramPieces[1].split("=")[1];
  140. var count = paramPieces[2].split("=")[1];
  141. var mediaId = id.substring(0, 3);
  142. if (mediaId != lastMediaId) {
  143. loadMediaBrowse(mediaId, function(){
  144. loadMediaContents(id, startPage, count, false);
  145. });
  146. }
  147. else {
  148. loadMediaContents(id, startPage, count, false);
  149. }
  150. lastMediaId = mediaId;
  151. break;
  152. }
  153. });
  154.  
  155. function browserIdentification() {
  156. browser = "other";
  157. // special treating for Safari
  158. if (navigator.userAgent.indexOf("Safari") != -1) browser = "Safari";
  159. if (navigator.userAgent.indexOf("KHTML") != -1) browser = "Safari";
  160. }
  161. function osIdentification() {
  162. os = navigator.platform;
  163. if (navigator.platform.indexOf("Mac") != -1) os = "Mac";
  164. }
  165.  
  166. function navigateTo(params){
  167. window.location.href = $.param.fragment(window.location.href, params, 2);
  168. }
  169.  
  170. function getLanguageFile(){
  171. // read server language file
  172. $.ajax("/webconfig/strings-" + statusData["language"] + ".json", {
  173. "success": function(data){
  174. languageFile = parseJson(data);
  175. },
  176. "error": function(){
  177. $.ajax("/webconfig/strings-en.json", function(data){
  178. languageFile = parseJson(data);
  179. });
  180. }
  181. });
  182. }
  183. function getConvertReadmeFile(){
  184. makeGetRequest("/webconfig/convert-readme.txt", {}, function(data){
  185. convertReadmeFile = data;
  186. convertReadmeFile = convertReadmeFile.replace(/(\r\n)|(\r)|(\n)/g, "<BR>");
  187. });
  188. }
  189.  
  190. //Get the value of a string given a key from the localized string translations.
  191. //key: The key to retrieve a string for.
  192. //getLong: Default false. If true, retrieve longValue from the translation object rather than value. longValue can be
  193. //used to store longer text that shouldn't necessarily always be displayed.
  194. function getString(key, getLong){
  195. if (languageFile[key]) {
  196. return (getLong) ? (languageFile[key].longValue) : (languageFile[key].value);
  197. } else {
  198. if (defaultLanguageFile[key]) {
  199. return (getLong) ? (defaultLanguageFile[key].longValue) : (defaultLanguageFile[key].value);
  200. } else {
  201. return "";
  202. }
  203. }
  204. }
  205.  
  206. //Replace the contents of all elements in html that have a "string" attribute with the matching value from the
  207. //translation file.
  208. //html: The HTML to perform the replacement on.
  209. function replaceStrings(html){
  210. var stringElements = $("[string]", html);
  211.  
  212. stringElements.each(function(i){
  213. $(this).html(getString($(this).attr("string")));
  214. });
  215. }
  216.  
  217.  
  218. // show or hide the content of subheaders.
  219. // The layout of each page will be saved. If the user comes back to a page the layout has not changed.
  220. function showToggleButtons(html){
  221. if (!(document.cookie)) return;
  222. var buttonElements = $(".toggleButton", html);
  223. buttonElements.each(function(i){
  224. var elem = $(this);
  225. var parent = elem.parents(".boxHeader");
  226. var nextHeader = $(parent).next();
  227. var id = elem.attr("id");
  228. var c = document.cookie;
  229. var a = c.split(";");
  230. for (var j=0;j<a.length;j++) {
  231. var cookieID = a[j].substring(0,a[j].indexOf("="));
  232. var cookieValue = a[j].substring(a[j].indexOf("=")+1, a[j].length);
  233. if (cookieID.indexOf(id) >= 0) {
  234. if (cookieValue.indexOf("show") >= 0) {
  235. nextHeader.show();
  236. if (nextHeader.hasClass("hideSubheaderBody")) nextHeader.removeClass("hideSubheaderBody"); // for I.E.
  237. $(".toggleText", elem).text(getString("hide"));
  238. elem.removeClass("hidden");
  239. elem.addClass("showing");
  240. }
  241. }
  242. }
  243. });
  244. }
  245.  
  246. //Call a handler function for each element in html that has a "key" attribute to display data.
  247. //html: The HTML to perform the replacement on.
  248. //responseData: The data object to retrieve the data from.
  249. //handler: The handler that should be called when an element with a "key" attribute is discovered. Handlers should
  250. //have the function signature (element, key, data) where element is the affected element, key is the data's key,
  251. //and data is the data collection object.
  252. function replaceData(html, responseData, handler){
  253. var dataElements = $("[key]", html);
  254. dataElements.each(function(i){
  255. var dataElement = $(this);
  256. var value = responseData[dataElement.attr("key")];
  257. if (handler) {
  258. handler(dataElement, dataElement.attr("key"), value);
  259. }
  260. else {
  261. dataElement.html(value);
  262. }
  263.  
  264. });
  265. }
  266.  
  267. //Split data using a separator character and store the resulting array.
  268. //responseData: The data to split.
  269. //dataCollection: The data object in which to store the data.
  270. //dataKey: The key used to store the data.
  271. //dataSeparator: The separator character.
  272. function parseData(responseData, dataCollection, dataCollectionOrig, dataKey, dataSeparator){
  273. var responsePieces = responseData.split(dataSeparator);
  274. dataCollection[dataKey] = responsePieces;
  275. dataCollectionOrig[dataKey] = responsePieces;
  276. }
  277.  
  278. //Split a collection of data that is in name/value pair form (e.g. /rpc/get_all) and store it in a data object.
  279. //The key becomes the first part of the split, and the value becomes the second (v=0 would be stored as {"v": 0}).
  280. //responseData: The data to split.
  281. //dataCollection: The data object in which to store the data. The data can be changed by the user.
  282. //dataCollectionOrig: The data object in which to store the data. These data are not changed by the user.
  283. //separatorChar: The character that separates the name/value pairs.
  284. function parseSeparatedData(responseData, dataCollection, dataCollectionOrig, separatorChar){
  285. var responsePieces = responseData.split("\n");
  286. $.each(responsePieces, function(i, value){
  287. var pieceArray = value.split(separatorChar);
  288. if (pieceArray.length == 2) {
  289. var cleanedData = pieceArray[1].replace(/\r/g, "");
  290. dataCollection[pieceArray[0]] = cleanedData;
  291. dataCollectionOrig[pieceArray[0]] = cleanedData;
  292. }
  293. else {
  294. var responseData = new Array(pieceArray.length - 1);
  295. $.each(pieceArray, function(i, value){
  296. if (pieceArray[i + 1]) {
  297. var cleanedData = pieceArray[i + 1].replace(/\r/g, "");
  298. responseData[i] = cleanedData;
  299. }
  300. });
  301. dataCollection[pieceArray[0]] = responseData;
  302. dataCollectionOrig[pieceArray[0]] = responseData;
  303. }
  304. });
  305. }
  306.  
  307. //A generic wrapper for making AJAX GET requests.
  308. //url: The url to make the request to.
  309. //params: A collection of objects to be passed as querystring arguments. Use the format {"key": value}. For example,
  310. //[{"uuid": 1234}, {"example": true}] will be passed as ?uuid=1234&example=true in the querystring.
  311. //callback: The callback to be called after the request finishes.
  312. function makeGetRequest(url, params, callback){
  313. var urlParams = "";
  314. var separatorChar = "?";
  315. if (params) {
  316. $.each(params, function(i, value){
  317. urlParams += separatorChar + i + "=" + value;
  318. separatorChar = "&";
  319. });
  320. }
  321. $.get(url + urlParams, function(response){
  322. if (callback) {
  323. callback(response);
  324. }
  325. });
  326. }
  327.  
  328. //A generic wrapper for making AJAX POST requests.
  329. //url: The url to make the request to.
  330. //params: A collection of objects to be passed as querystring arguments. Use the format {"key": value}. For example,
  331. //[{"uuid": 1234}, {"example": true}] will be passed as ?uuid=1234&example=true in the querystring.
  332. //data: The data to be passed during the POST request.
  333. //callback: The callback to be called after the request finishes.
  334. function makePostRequest(url, params, data, callback){
  335. var urlParams = "";
  336. var separatorChar = "?";
  337. if (params) {
  338. $.each(params, function(i, value){
  339. urlParams += separatorChar + i + "=" + value;
  340. separatorChar = "&";
  341. });
  342. }
  343. $.post(url + urlParams, data, function(response){
  344. if (callback) {
  345. callback(response);
  346. }
  347. });
  348. }
  349.  
  350. function showLoadingGraphic(){
  351. $(".serverSettingsContentWrapper").addClass("loading");
  352. if (loadingGraficActiv) window.clearInterval(loadingGraficActiv);
  353. loadingGraficActiv = window.setInterval("hideLoadingGraphic()", 8000);
  354. }
  355.  
  356. function hideLoadingGraphic(){
  357. window.clearInterval(loadingGraficActiv);
  358. loadingGraficActiv = null;
  359. if ($(".serverSettingsContentWrapper").hasClass("loading"))
  360. $(".serverSettingsContentWrapper").removeClass("loading");
  361. }
  362.  
  363. function onLanguageFetched(){
  364. replaceStrings($(document));
  365. $(window).trigger("hashchange");
  366. }
  367.  
  368. function setVisitLinks() {
  369. var id1 = document.getElementById("visitLink1");
  370. var id2 = document.getElementById("visitLink2");
  371. var id3 = document.getElementById("visitLink3");
  372. var id4 = document.getElementById("visitLink4");
  373. var id11 = document.getElementById("legalLink1");
  374. if (noMediaFusionServer || myTwonkyDisabled) {
  375. // Twonky
  376. id1.innerHTML = "<a href='http://www.twonky.com/about.aspx' target='_blank' string='twonky.com'></a>";
  377. // Mobile Apps
  378. id2.innerHTML = "<a href='http://www.twonky.com/products/twonkymobile/default.aspx' target='_blank' string='mobileApps'></a>";
  379. // Help center
  380. id3.innerHTML = "<a href='http://community.twonky.com/twonky' target='_blank' string='helpCenter'></a>";
  381. // -
  382. id4.innerHTML = "";
  383. // Licensing Information
  384. id11.innerHTML = "<a href='' onclick='navigateTo(\"licenseinfo\"); return false;' string='licensinginfo'></a>";
  385. } else {
  386. // myTwonky
  387. id1.innerHTML = "<a href='http://my.twonky.com' target='_blank' string='mytwonky.com'></a>";
  388. // Twonky
  389. id2.innerHTML = "<a href='http://www.twonky.com/about.aspx' target='_blank' string='twonky.com'></a>";
  390. // Mobile Apps
  391. id3.innerHTML = "<a href='http://www.twonky.com/products/twonkymobile/default.aspx' target='_blank' string='mobileApps'></a>";
  392. // Help center
  393. id4.innerHTML = "<a href='http://community.twonky.com/twonky' target='_blank' string='helpCenter'></a>";
  394. // Licensing Information
  395. id11.innerHTML = "<a href='' onclick='navigateTo(\"licenseinfo\"); return false;' string='licensinginfo'></a>";
  396. }
  397. }
  398.  
  399. //Initialize the Settings application by first reading the user's language setting, then loading the language file
  400. //and calling loadStatus.
  401. function initPage(){
  402. if (top != self) {
  403. // page is in an iFrame; show no header and footer
  404. $("#headWrapper").hide();
  405. $("#footer").hide();
  406. }
  407. // identify browser and OS
  408. browserIdentification();
  409. osIdentification();
  410. // get the WebDav server url
  411. makeGetRequest("/rpc/get_webdav_link", {}, function(response){
  412. statusData["syncurl"] = response;
  413. if (statusData["syncurl"].toLowerCase() == "nowebdav") noWebDavServer = true;
  414. });
  415. // get the portal links
  416. makeGetRequest("/rpc/portal_page?login", {}, function(response){
  417. statusData["portallogin"] = response;
  418. });
  419. makeGetRequest("/rpc/portal_page?register", {}, function(response){
  420. statusData["portalregister"] = response;
  421. });
  422. makeGetRequest("/rpc/portal_page?login24", {}, function(response){
  423. statusData["portallogin24"] = response + "/signin?pvx-orig-url=" + document.URL;
  424. });
  425. // connect media fusion server to update the server myTwonky status
  426. initialPortalCheck();
  427. $(".toggleButton").live("click", function(obj){
  428. toggleContainer($(obj.currentTarget));
  429. });
  430. getConvertReadmeFile();
  431. makeGetRequest("/rpc/get_all", {}, function(response){
  432. parseSeparatedData(response, statusData, statusDataOrig, "=");
  433. //Handle the version case separately.
  434. //get_all, info_status and version return a "version" property.
  435. //get_all.version is only set if the server comes with NMC
  436. statusData["fullversion"] = statusData.version;
  437. makeGetRequest("/webconfig/strings-en.json", {}, function(data){
  438. defaultLanguageFile = parseJson(data);
  439. languageFile = parseJson(data);
  440. makeGetRequest("/webconfig/strings-"+statusData["language"]+".json", {}, function(data2){
  441. languageFile = parseJson(data2);
  442. onLanguageFetched();
  443. });
  444. });
  445. var mediafusionServerUrl = statusData["mediafusionserverurl"];
  446. // Setting empty value to 'mediafusionserverurl' is used to indicate
  447. // that the MediaFusion is disabled, and must not be shown on the config page.
  448. if (mediafusionServerUrl.length < 1) noMediaFusionServer = true;
  449. if (statusData["disablemytwonky"] == 1) myTwonkyDisabled = true;
  450. setVisitLinks(); // set links to myTwonky and twonky in footer
  451. });
  452. }
  453.  
  454. function onEventClick() {
  455. if (!(changesMade || inputFieldClicked)) {
  456. inputFieldClicked = true;
  457. // give "save"-button a new look
  458. $("#saveButton").addClass("confirm");
  459. }
  460. }
  461. function onEventChange(){
  462. if (!changesMade) {
  463. changesMade = true;
  464. // give "save"-button a new look
  465. if (!$("#saveButton").hasClass("confirm")) $("#saveButton").addClass("confirm");
  466. }
  467. }
  468. function resetChanged(){
  469. inputFieldClicked = false;
  470. changesMade = false;
  471. // reset the look of the "save"-button
  472. if ($("#saveButton").hasClass("confirm")) $("#saveButton").removeClass("confirm");
  473. }
  474.  
  475. //If the user has changed any inputs on the page, display a dialog to warn them and prompt them to save changes.
  476. //Otherwise, navigate away.
  477. //navFunctionStr: A string indicating the function that should be called when navigation is performed
  478. //(e.g. "loadStatus()").
  479. function checkChanges(navFunctionStr){
  480. if (changesMade) {
  481. showDialogOverlay(function(){
  482. return getString("saveprompt");
  483. }, {}, {
  484. 1: {
  485. text: getString("savechanges"),
  486. onclick: saveHandler + " " + "hideDialogOverlay(); " + navFunctionStr
  487. },
  488. 2: {
  489. text: getString("discardchanges"),
  490. onclick: "changesMade = false; hideDialogOverlay(); " + navFunctionStr
  491. }
  492. });
  493. }
  494. else {
  495. eval(navFunctionStr);
  496. }
  497. }
  498.  
  499. function populateSettingsNav(){
  500. if ($(".serverSettingsLeftNav").length == 0) {
  501. makeGetRequest("/webconfig/settings-nav.htm", {}, function(response){
  502. var responseHtml = $(response);
  503. replaceStrings(responseHtml);
  504. $("a", "#nav").removeClass("active");
  505. $(".serverSettingsContentWrapper").removeClass("contentDisplay");
  506. $("#leftNavContainer").html(responseHtml);
  507. if (noWebDavServer) {
  508. // remove nav-tree synchronization
  509. $("#nav_synchronization").remove();
  510. }
  511. });
  512. }
  513. }
  514.  
  515. //Clear the selection on the currently selected left navigation item and highlight the new one. Cancel the
  516. //udpate timer if it exists.
  517. //currentNav: The newly clicked navigation item.
  518. function highlightNav(currentNav){
  519. if (activeNav) {
  520. activeNav.removeClass("current");
  521. if (updateTimer) {
  522. clearTimeout(updateTimer);
  523. }
  524. }
  525. currentNav.addClass("current");
  526. activeNav = currentNav;
  527. }
  528.  
  529. function refreshPortalInfo() {
  530. var c = document.cookie;
  531. var a = c.split(";");
  532. for (var j=0;j<a.length;j++) {
  533. var cookieID = a[j].substring(0,a[j].indexOf("="));
  534. var cookieValue = a[j].substring(a[j].indexOf("=")+1, a[j].length);
  535. if (cookieID.indexOf("login24") >= 0) {
  536. if (cookieValue.indexOf("true") >= 0) {
  537. document.cookie = "login24=false;";
  538. startPortalCheckTimer();
  539. }
  540. }
  541. }
  542. }
  543.  
  544. // accountingstatus:
  545. //#define ACCOUNTING_TRIAL_VERSION 1 "TwonkyServer"
  546. //#define ACCOUNTING_REGISTERED_VERSION_TS_ONLY 2
  547. //#define ACCOUNTING_REGISTERED_VERSION_TSTML 3
  548. //#define ACCOUNTING_REGISTERED_VERSION_TSTMF 4
  549. //#define ACCOUNTING_PORTAL_VERSION 5 "TwonkyServer Free"
  550. //#define ACCOUNTING_PREMIUM_VERSION 6 "TwonkyServer Premium"
  551. //#define ACCOUNTING_OEM_VERSION 7
  552. function getServerType(accStatus) {
  553. var str = "TwonkyServer";
  554. switch (accStatus) {
  555. case "2": str = "TwonkyServer";
  556. break;
  557. case "5": str = "TwonkyServer free";
  558. break;
  559. case "6": str = "TwonkyServer Premium";
  560. break;
  561. }
  562. return str;
  563. }
  564.  
  565. // ------------------------
  566. // status page
  567. // ------------------------
  568. //Load data for the Status page.
  569. //isInitial: Default false. /rpc/get_all is called on application load, so set isInitial to true to avoid a duplicate
  570. //call.
  571. function loadStatus(isInitial){
  572. returnedCalls = 0;
  573. expectedCalls = (isInitial) ? 8 : 10;
  574. saveHandler = "function(){};"
  575. inputFieldClicked = false;
  576. changesMade = false;
  577.  
  578. showLoadingGraphic();
  579. refreshPortalInfo(); // check the portal status after a login from a free server after 24 hours
  580.  
  581. if (!isInitial) {
  582. makeGetRequest("/rpc/get_all", {}, function(response){
  583. parseSeparatedData(response, statusData, statusDataOrig, "=");
  584. statusData["fullversion"] = statusData.version; // info_status returns the property "version" too
  585. returnedCalls++;
  586. if (expectedCalls == returnedCalls) {
  587. loadStatusHtml();
  588. hideLoadingGraphic();
  589. }
  590. });
  591. makeGetRequest("/rpc/get_webdav_link", {}, function(response){
  592. statusData["syncurl"] = response;
  593. returnedCalls++;
  594. if (statusData["syncurl"].toLowerCase() == "nowebdav") noWebDavServer = true;
  595. if (expectedCalls == returnedCalls) {
  596. loadStatusHtml();
  597. hideLoadingGraphic();
  598. }
  599. });
  600. }
  601.  
  602. makeGetRequest("/rpc/info_status", {}, function(response){
  603. parseSeparatedData(response, statusData, statusDataOrig, "|");
  604. statusData["serverversion"] = statusData.version; // get_all returns the property "version" too
  605. // statusData["servertype"] = getServerType(statusData["licensestatus"]);
  606. // statusData["servertypepart2"] = statusData["servertype"];
  607. returnedCalls++;
  608. if (expectedCalls == returnedCalls) {
  609. loadStatusHtml();
  610. hideLoadingGraphic();
  611. }
  612. });
  613. // function get_server_type restored - should be retired again. See also chapter advanced!
  614. makeGetRequest("/rpc/get_server_type", {}, function(response){
  615. statusData["servertype"] = response;
  616. statusData["servertypepart2"] = response;
  617. advanced["servertype"] = response;
  618. returnedCalls++;
  619. if (expectedCalls == returnedCalls) {
  620. loadStatusHtml();
  621. hideLoadingGraphic();
  622. }
  623. });
  624.  
  625. makeGetRequest("/rpc/get_friendlyname", {}, function(response){
  626. statusData["friendlynamestring"] = response;
  627. returnedCalls++;
  628. if (expectedCalls == returnedCalls) {
  629. loadStatusHtml();
  630. hideLoadingGraphic();
  631. }
  632. });
  633.  
  634. makeGetRequest("/rpc/info_nics", {}, function(response){
  635. parseData(response, statusData, statusDataOrig, "nics", "\n");
  636. returnedCalls++;
  637. if (expectedCalls == returnedCalls) {
  638. loadStatusHtml();
  639. hideLoadingGraphic();
  640. }
  641. });
  642.  
  643. makeGetRequest("/rpc/stream_active", {}, function(response){
  644. parseData(response, statusData, statusDataOrig, "streams", "SA:");
  645. returnedCalls++;
  646. if (expectedCalls == returnedCalls) {
  647. loadStatusHtml();
  648. hideLoadingGraphic();
  649. }
  650. });
  651.  
  652. makeGetRequest("/rpc/get_portal_info", {}, function(response){
  653. statusData["portalinfo"] = response;
  654. returnedCalls++;
  655. if (expectedCalls == returnedCalls) {
  656. loadStatusHtml();
  657. hideLoadingGraphic();
  658. }
  659. });
  660.  
  661. makeGetRequest("/rpc/get_option?portalusername", {}, function(response){
  662. statusData["portalusername"] = response;
  663. returnedCalls++;
  664. if (expectedCalls == returnedCalls) {
  665. loadStatusHtml();
  666. hideLoadingGraphic();
  667. }
  668. });
  669.  
  670.  
  671. $.ajax({
  672. url: "/rpc/get_timeout_period",
  673. success: function(response){
  674. returnedCalls++;
  675. statusData["lastlogin"] = response;
  676. if (expectedCalls == returnedCalls) {
  677. loadStatusHtml();
  678. hideLoadingGraphic();
  679. }
  680. },
  681. error: function(response){
  682. returnedCalls++;
  683. if (expectedCalls == returnedCalls) {
  684. loadStatusHtml();
  685. hideLoadingGraphic();
  686. }
  687. }
  688. });
  689. }
  690.  
  691. function handleStatusData(element, key, data){
  692. var returnValue = "";
  693. switch (key) {
  694. case "restartpending":
  695. returnValue = (data == 0) ? (getString("no")) : (getString("yes"));
  696. break;
  697. case "wmdrmstatus":
  698. returnValue = (data) ? (data.toUpperCase()) : ("");
  699. break;
  700. case "uptime":
  701. var days = data[0];
  702. var timePieces = data[1].split(":");
  703. returnValue = days + " " + getString("days") + ", " + timePieces[0] + " " + getString("hours") + ", " + timePieces[1] + " " + getString("minutes") + ", " + timePieces[2] + " " + getString("seconds");
  704. break;
  705. case "syncurl":
  706. returnValue = (data.toLowerCase() == "nowebdav") ? ("-") : (data);
  707. break;
  708. case "nics":
  709. if (data) {
  710. $.each(data, function(i, value){
  711. if (value.length > 0 && value.lastIndexOf("127.0.0.1") == -1) {
  712. var nicPieces = value.split(",");
  713. var mac = (nicPieces[1]) ? (nicPieces[1]) : ("")
  714. returnValue += "<span class='nicIp'>" + nicPieces[0] + "</span>" + " " + mac + "<br />";
  715. }
  716. });
  717. }
  718. break;
  719. case "cdkey":
  720. if (statusData["licensestatus"] == "4") break; // OEM-version: do not show the key
  721. if (data && statusData["servertype"].toLowerCase().indexOf("free") == -1) {
  722. returnValue = '<div class="serverStatusLabel floatL">' + getString("cdkey") + '</div><div class="floatL">' + data + '</div><div class="clear"></div>';
  723. }
  724. break;
  725. case "licensestatus":
  726. //if ((!statusData["cdkey"] || data < 1) && statusData["servertype"].toLowerCase().indexOf("free") == -1) {
  727. if (data < 2) {
  728. //Remove the element's key to prevent it from being overwritten during the automatic update timer.
  729. element.attr("key", "nothing");
  730. returnValue += '<div class="boxHeader">\
  731. <span class="titleWrapper">\
  732. <span class="title">' + getString("licensekey") + '</span>\
  733. </span>\
  734. <div class="clear" />\
  735. </div>\
  736. <div><div>' +
  737. getString("licensekeycaption") +
  738. '</div><br />';
  739. if (os != "Mac") {
  740. // Windows, Linux: show 8 fields for license key
  741. for (var i = 0; i < 8; i++) {
  742. returnValue += '<input type="text" class="licenseKeyInput floatL" maxchars="4" onchange="onLicenseInput($(this))" onkeyup="onLicenseInput($(this)); onLicenseInputKeyUp(event)"></input>'
  743. }
  744. } else {
  745. // Mac: show one field for license key
  746. returnValue += '<input type="text" class="licenseKeyInputMac floatL" maxchars="39" onkeyup="onLicenseInputKeyUp(event)"></input>'
  747. }
  748.  
  749. returnValue += '<a class="actionbtn floatL" onclick="saveLicenseKey()" onmousedown="onButtonMouseDown(this)" onmouseup="onButtonMouseUp(this)">\
  750. <span class="actionbtn_l"></span>\
  751. <span class="actionbtn_c">' + getString("enter") + '</span>\
  752. <span class="actionbtn_r"></span>\
  753. </a>\
  754. <div class="clear"></div>'
  755.  
  756. switch (data) {
  757. case 1:
  758. returnValue += "<div class='error'>" + statusData["licensedays"] + " " + getString("daysremaining") + "</div>"
  759. break;
  760. case 2:
  761. case 3:
  762. case 4:
  763. break;
  764. default:
  765. returnValue += "<div class='error'>" + getString("license" + data) + "</div>"
  766. break;
  767. }
  768.  
  769. returnValue += '</div><div class="serverContentSpacer"></div>';
  770. }
  771. break;
  772. case "streams":
  773. returnValue = (data[1] > 0) ? (getString("activestreams")) : (getString("noactivestreams"));
  774. break;
  775. case "servertype":
  776. // show the server type and version
  777. // free: Twonky 7.0 (servertype, fullversion)
  778. // premium: TwonkyServer Premium 7.0 (servertype, fullversion)
  779. // standard: Twonky 7.0 Special (servertype, fullversion, servertypepart2)
  780. var serverType = data.toLowerCase();
  781. if (serverType.lastIndexOf("premium") > -1) {
  782. returnValue = getString("premiumserver");
  783. }
  784. else
  785. if (serverType.lastIndexOf("free") > -1) {
  786. returnValue = getString("freeserver");
  787. }
  788. else {
  789. returnValue = getString("twonkyserver");
  790. }
  791. break;
  792. case "servertypepart2":
  793. var serverType = data.toLowerCase();
  794. if ((serverType.lastIndexOf("premium") == -1) && (serverType.lastIndexOf("free") == -1)) {
  795. returnValue = getString("twonkyservertextpart2");
  796. }
  797. else return "";
  798. break;
  799. case "portalinfo":
  800. var serverType = statusData["servertype"];
  801. if (noMediaFusionServer || myTwonkyDisabled) break;
  802. switch (data) {
  803. case "notregistered":
  804. if (serverType.toLowerCase().lastIndexOf("free") > -1) {
  805. if (browser == "other") {
  806. returnValue = '<div>' +
  807. getString("registrationrequiredcaption") +
  808. '</div>\
  809. <div class="smallServerContentSpacer"></div>\
  810. <div><a class="actionbtnmd bold" onmousedown="onButtonMouseDown(this)" onmouseup="onButtonMouseUp(this)" onclick="openPortalLink(\'register\')"><span class="actionbtn_l"></span><span class="actionbtn_c">' +
  811. getString("registerserver") +
  812. '</span><span class="actionbtn_r"></span></a></div>\
  813. <div class="serverContentSpacer"></div>';
  814. } else {
  815. // Safari browser
  816. returnValue = '<div>' +
  817. getString("registrationrequiredcaption") +
  818. '</div>\
  819. <div class="smallServerContentSpacer"></div>\
  820. <div><a class="actionbtnmd bold" href="' + statusData["portalregister"] + '" target="_blank" onclick="javascript:startPortalCheckTimerOnClick(\'register\')"><span class="actionbtn_l"></span><span class="actionbtn_c">' +
  821. getString("registerserver") +
  822. '</span><span class="actionbtn_r"></span></a></div>\
  823. <div class="serverContentSpacer"></div>';
  824. }
  825. }
  826. else {
  827. if (browser == "other") {
  828. returnValue = '<div>' +
  829. getString("registrationoptionalcaption") +
  830. '</div>\
  831. <div class="smallServerContentSpacer"></div>\
  832. <div><a class="actionbtnmd bold" onmousedown="onButtonMouseDown(this)" onmouseup="onButtonMouseUp(this)" onclick="openPortalLink(\'register\')"><span class="actionbtn_l"></span><span class="actionbtn_c">' +
  833. getString("registerserver") +
  834. '</span><span class="actionbtn_r"></span></a></div>\
  835. <div class="serverContentSpacer"></div>';
  836. } else {
  837. // Safari browser
  838. returnValue = '<div>' +
  839. getString("registrationoptionalcaption") +
  840. '</div>\
  841. <div class="smallServerContentSpacer"></div>\
  842. <div><a class="actionbtnmd bold" href="' + statusData["portalregister"] + '" target="_blank" onclick="javascript:startPortalCheckTimerOnClick(\'register\')"><span class="actionbtn_l"></span><span class="actionbtn_c">' +
  843. getString("registerserver") +
  844. '</span><span class="actionbtn_r"></span></a></div>\
  845. <div class="serverContentSpacer"></div>';
  846. }
  847. }
  848. break;
  849. case "notloggedin":
  850. if (browser == "other") {
  851. returnValue = '<div>' +
  852. getString("loginneededcaption") +
  853. '</div>\
  854. <div class="smallServerContentSpacer"></div>\
  855. <div><a class="actionbtnmd bold" onmousedown="onButtonMouseDown(this)" onmouseup="onButtonMouseUp(this)" onclick="openPortalLink(\'login\')"><span class="actionbtn_l"></span><span class="actionbtn_c">' +
  856. getString("login") +
  857. '</span><span class="actionbtn_r"></span></a></div>\
  858. <div class="serverContentSpacer"></div>';
  859. } else {
  860. // Safari browser
  861. returnValue = '<div>' +
  862. getString("loginneededcaption") +
  863. '</div>\
  864. <div class="smallServerContentSpacer"></div>\
  865. <div><a class="actionbtnmd bold" href="' + statusData["portallogin"] + '" target="_blank" onclick="javascript:startPortalCheckTimerOnClick(\'login\')"><span class="actionbtn_l"></span><span class="actionbtn_c">' +
  866. getString("login") +
  867. '</span><span class="actionbtn_r"></span></a></div>\
  868. <div class="serverContentSpacer"></div>';
  869. }
  870. break;
  871. case "portaldisabled":
  872. returnValue = getString("portaldisabled") + '<div class="serverContentSpacer"></div>';
  873. break;
  874. case "useronline":
  875. var renewStr = "";
  876. if (serverType.toLowerCase().lastIndexOf("free") > -1) {
  877. serverType = "free";
  878. if (statusData["lastlogin"].indexOf(":") > 0) {
  879. // format hours:minutes
  880. var timePieces = statusData["lastlogin"].split(":");
  881. var hours = timePieces[0];
  882. var minutes = timePieces[1];
  883. var timeoutStr = getString("renewlicense");
  884. renewStr = timeoutStr.replace("{0}", hours).replace("{1}", minutes);
  885. if (browser == "other") {
  886. renewStr = renewStr.replace("myTwonky.com", "<a class=\'inlineLink\' href=\"javascript:openPortalLink(\'login\')\">myTwonky.com</a>");
  887. } else {
  888. // Safari browser
  889. renewStr = renewStr.replace("myTwonky.com", "<a class=\'inlineLink\' href=\'" + statusData["portallogin"] + "\' target=\'_blank\' onclick=\'javascript:startPortalCheckTimerOnClick(\"register\")\'>myTwonky.com</a>");
  890. }
  891. } else {
  892. // in seconds
  893. var seconds1 = statusData["lastlogin"];
  894. if (seconds1 > 0) {
  895. var minutes1 = (seconds1 - (seconds1 % 60)) / 60;
  896. var minutes = minutes1 % 60;
  897. var hours = (minutes1 - minutes) / 60;
  898. } else {
  899. var hours = "0";
  900. var minutes = "00";
  901. }
  902. if (hours > 23) {
  903. // show remaining days
  904. var days = (hours - (hours % 24)) / 24;
  905. var timeoutStr = getString("renewlicenseindays");
  906. renewStr = timeoutStr.replace("{0}", days);
  907. if (browser == "other") {
  908. renewStr = renewStr.replace("myTwonky.com", "<a class=\'inlineLink\' href=\"javascript:openPortalLink(\'login\')\">myTwonky.com</a>");
  909. } else {
  910. // Safari browser
  911. renewStr = renewStr.replace("myTwonky.com", "<a class=\'inlineLink\' href=\'" + statusData["portallogin"] + "\' target=\'_blank\' onclick=\'javascript:startPortalCheckTimerOnClick(\"register\")\'>myTwonky.com</a>");
  912. }
  913. } else {
  914. // show remaining hours and minutes
  915. var timeoutStr = getString("renewlicense");
  916. renewStr = timeoutStr.replace("{0}", hours).replace("{1}", minutes);
  917. if (browser == "other") {
  918. renewStr = renewStr.replace("myTwonky.com", "<a class=\'inlineLink\' href=\"javascript:openPortalLink(\'login\')\">myTwonky.com</a>");
  919. } else {
  920. // Safari browser
  921. renewStr = renewStr.replace("myTwonky.com", "<a class=\'inlineLink\' href=\'" + statusData["portallogin"] + "\' target=\'_blank\' onclick=\'javascript:startPortalCheckTimerOnClick(\"register\")\'>myTwonky.com</a>");
  922. }
  923. }
  924. }
  925. }
  926. returnValue = getString("loggedinas") + " " + statusData["portalusername"] + '<br /><div>' + renewStr + '<div class="serverContentSpacer"></div>';
  927. break;
  928. case "connectionissue":
  929. returnValue = getString("connectionissue") + '<div class="serverContentSpacer"></div>';
  930. break;
  931. case "connecting":
  932. returnValue = getString("portalconnecting") + '<div class="serverContentSpacer"></div>';
  933. break;
  934. }
  935. break;
  936. default:
  937. returnValue = data;
  938. break;
  939. }
  940. element.html(returnValue);
  941. }
  942.  
  943. function onLicenseInput(input){
  944. if (input.val().match(/^[A-Z0-9]{4}(-[A-Z0-9]{4}){7}$/)) {
  945. var keyPieces = input.val().split("-");
  946. var inputs = $(".licenseKeyInput");
  947. $.each(inputs, function(i, element){
  948. $(element).val(keyPieces[i]);
  949. });
  950. }
  951. else {
  952. if (input.val().length > input.attr("maxchars")) {
  953. input.val(input.val().substring(0, input.attr("maxchars")));
  954. }
  955. if (input.val().length == input.attr("maxchars")) {
  956. input.next().focus();
  957. }
  958. }
  959. }
  960.  
  961. function onLicenseInputKeyUp(event){
  962. if (event.which == 13) {
  963. saveLicenseKey();
  964. }
  965. }
  966.  
  967. function saveLicenseKey(){
  968. var key = "";
  969. resetChanged();
  970. if (os != "Mac") {
  971. var inputs = $(".licenseKeyInput");
  972. $.each(inputs, function(i, element){
  973. key += $(element).val();
  974. if (i != inputs.length - 1) {
  975. key += "-";
  976. }
  977. });
  978. } else key = $(".licenseKeyInputMac")[0].value;
  979. var data = "cdkey=" + key + "\n";
  980. makeGetRequest("/rpc/set_option?"+data, {}, function(response) {});
  981. //location.reload();
  982. var timerKey = setTimeout("reloadSide()",30);
  983. }
  984. function reloadSide() {
  985. location.reload();
  986. }
  987.  
  988. function initialPortalCheck() {
  989. // twonky server connect to media fusion server to update the portal data
  990. makeGetRequest("/rpc/get_portal_info?onlineStatus", {}, function(response) {});
  991. }
  992. function openPortalLink(arg){
  993. // login with redirect to config pages if 24 hours are over - only free server
  994. if (arg == "login24") {
  995. // call the portal with the current url (server config page) as parameter
  996. // example call: window.open("http://staging-portal.twonky.com/signin?pvx-orig-url=http://127.0.0.1:9000", ....)
  997. // set cookie. At restart update server portal data.
  998. document.cookie = "login24=true;";
  999. makeGetRequest("/rpc/portal_page?" + arg, {}, function(response){
  1000. window.open(response+"/signin?pvx-orig-url="+document.URL, "_self", 'menubar=yes,scrollbars=yes,status=yes,toolbar=yes,resizable=yes');
  1001. });
  1002. }
  1003. if (arg == "register") {
  1004. makeGetRequest("/rpc/portal_page?" + arg, {}, function(response){
  1005. window.open(response, "PortalPage", 'menubar=yes,scrollbars=yes,status=yes,toolbar=yes,resizable=yes');
  1006. });
  1007. }
  1008. if (arg == "login") {
  1009. makeGetRequest("/rpc/portal_page?" + arg, {}, function(response){
  1010. window.open(response, "PortalPage", 'menubar=yes,scrollbars=yes,status=yes,toolbar=yes,resizable=yes');
  1011. });
  1012. }
  1013. startPortalCheckTimer();
  1014. }
  1015. function startPortalCheckTimer() {
  1016. if (portalTimerIntervalCount == 0) {
  1017. // start a timer to update the server portal data
  1018. portalTimerIntervalCount = 1;
  1019. portalTimerInterval = portalTimerInterval1;
  1020. portalTimer = setInterval(checkPortalStatus, portalTimerInterval1);
  1021. }
  1022. }
  1023. function startPortalCheckTimerOnClick(arg) {
  1024. if (arg == "login24") document.cookie = "login24=true;";
  1025. startPortalCheckTimer();
  1026. return true;
  1027. }
  1028. function disassociatePortalLink(servertype) {
  1029. if (servertype == "free") var msg = getString("dialog_portaldisassociatefree");
  1030. else var msg = getString("dialog_portaldisassociatepremium");
  1031. confirmDialog(msg,"confirmDisassociatePortalLink()");
  1032. }
  1033. function confirmDisassociatePortalLink() {
  1034. hideDialogOverlay();
  1035. makeGetRequest("/rpc/portal_disassociate", {}, function(response){});
  1036. $("#portaldisassociation").hide();
  1037. }
  1038. function checkPortalStatus() {
  1039. // twonky server calls media fusion server
  1040. makeGetRequest("/rpc/get_portal_info?onlineStatus", {}, function(response){
  1041. if (response == "online") {
  1042. portalTimerInterval = portalTimerInterval3;
  1043. portalTimerIntervalCount = portalTimerInterval3Count;
  1044. };
  1045. });
  1046. // update status page
  1047. updateStatus();
  1048. // increase interval counter
  1049. portalTimerIntervalCount ++;
  1050. if (portalTimerInterval == portalTimerInterval1) {
  1051. if (portalTimerIntervalCount > portalTimerInterval1Count) {
  1052. // stop timer and start timer with interval 2
  1053. clearInterval(portalTimer);
  1054. portalTimerIntervalCount = 1;
  1055. portalTimerInterval = portalTimerInterval2;
  1056. portalTimer = setInterval(checkPortalStatus, portalTimerInterval2);
  1057. }
  1058. }
  1059. if (portalTimerInterval == portalTimerInterval2) {
  1060. if (portalTimerIntervalCount > portalTimerInterval2Count) {
  1061. // stop timer and start timer with interval 3
  1062. clearInterval(portalTimer);
  1063. portalTimerIntervalCount = 1;
  1064. portalTimerInterval = portalTimerInterval3;
  1065. portalTimer = setInterval(checkPortalStatus, portalTimerInterval3);
  1066. }
  1067. }
  1068. if (portalTimerInterval == portalTimerInterval3) {
  1069. if (portalTimerIntervalCount > portalTimerInterval3Count) {
  1070. // stop portal timer
  1071. clearInterval(portalTimer);
  1072. portalTimerIntervalCount = 0;
  1073. }
  1074. }
  1075. }
  1076.  
  1077. function loadStatusHtml(){
  1078. makeGetRequest("/webconfig/status.htm", {}, function(response){
  1079. var responseHtml = $(response);
  1080. replaceStrings(responseHtml);
  1081. replaceData(responseHtml, statusData, handleStatusData);
  1082. showToggleButtons(responseHtml);
  1083. $(".serverSettingsContentWrapper").html(responseHtml);
  1084. if (noMediaFusionServer || myTwonkyDisabled) {
  1085. $("#portalHeader").addClass("hideSubheader");
  1086. }
  1087. if (noWebDavServer) {
  1088. $("#statusSyncUrl").hide();
  1089. }
  1090. highlightNav($("#nav_status"));
  1091. hideLoadingGraphic();
  1092. if (statusData["portalinfo"] == "connecting")
  1093. updateTimer = setInterval(updateStatusTimerCheck, updateTimerInterval1);
  1094. else
  1095. updateTimer = setInterval(updateStatus, updateTimerInterval);
  1096. });
  1097. }
  1098.  
  1099. // special action for status update
  1100. // The portal info is updated every 2 seconds.
  1101. // If the portal is "online" the page is updated immediatly and the update timer is set to 30 seconds.
  1102. // The page is updated every 10 seconds three times (updateTimerInterval1),
  1103. // later every 30 seconds (updateTimerInterval)
  1104. function updateStatusTimerCheck() {
  1105. makeGetRequest("/rpc/get_portal_info", {}, function(response){
  1106. statusData["portalinfo"] = response;
  1107. updateTimerInterval1Count++;
  1108. if (statusData["portalinfo"] != "connecting") {
  1109. clearInterval(updateTimer);
  1110. updateTimer = setInterval(updateStatus, updateTimerInterval);
  1111. updateStatus();
  1112. }
  1113. if (updateTimerInterval1Count >= 30) {
  1114. clearInterval(updateTimer);
  1115. updateTimer = setInterval(updateStatus, updateTimerInterval);
  1116. }
  1117. });
  1118. }
  1119.  
  1120. function updateStatus(){
  1121. returnedCalls = 0;
  1122. expectedCalls = 5;
  1123. showLoadingGraphic();
  1124.  
  1125. makeGetRequest("/rpc/info_status", {}, function(response){
  1126. parseSeparatedData(response, statusData, statusDataOrig, "|");
  1127. statusData["serverversion"] = statusData.version; // get_all returns the property "version" too
  1128. returnedCalls++;
  1129. if (expectedCalls == returnedCalls) {
  1130. replaceData($(".serverSettingsContentWrapper"), statusData, handleStatusData);
  1131. hideLoadingGraphic();
  1132. }
  1133. });
  1134.  
  1135. makeGetRequest("/rpc/get_all", {}, function(response){
  1136. parseSeparatedData(response, statusData, statusDataOrig, "=");
  1137. statusData["fullversion"] = statusData.version; // info_status returns the property "version" too
  1138. returnedCalls++;
  1139. if (expectedCalls == returnedCalls) {
  1140. replaceData($(".serverSettingsContentWrapper"), statusData, handleStatusData);
  1141. hideLoadingGraphic();
  1142. }
  1143. });
  1144.  
  1145. makeGetRequest("/rpc/get_portal_info", {}, function(response){
  1146. statusData["portalinfo"] = response;
  1147. returnedCalls++;
  1148. if (expectedCalls == returnedCalls) {
  1149. replaceData($(".serverSettingsContentWrapper"), statusData, handleStatusData);
  1150. hideLoadingGraphic();
  1151. }
  1152. });
  1153.  
  1154. makeGetRequest("/rpc/get_option?portalusername", {}, function(response){
  1155. statusData["portalusername"] = response;
  1156. returnedCalls++;
  1157. if (expectedCalls == returnedCalls) {
  1158. replaceData($(".serverSettingsContentWrapper"), statusData, handleStatusData);
  1159. hideLoadingGraphic();
  1160. }
  1161. });
  1162.  
  1163. $.ajax({
  1164. url: "/rpc/get_timeout_period",
  1165. success: function(response){
  1166. returnedCalls++;
  1167. statusData["lastlogin"] = response;
  1168. if (expectedCalls == returnedCalls) {
  1169. replaceData($(".serverSettingsContentWrapper"), statusData, handleStatusData);
  1170. hideLoadingGraphic();
  1171. }
  1172. },
  1173. error: function(response){
  1174. returnedCalls++;
  1175. if (expectedCalls == returnedCalls) {
  1176. replaceData($(".serverSettingsContentWrapper"), statusData, handleStatusData);
  1177. hideLoadingGraphic();
  1178. }
  1179. }
  1180. });
  1181. }
  1182.  
  1183.  
  1184. // ------------------------
  1185. // setup page
  1186. // ------------------------
  1187. function loadSetup(){
  1188. returnedCalls = 0;
  1189. expectedCalls = 2;
  1190. saveHandler = "submitSetupData();"
  1191. inputFieldClicked = false;
  1192. changesMade = false;
  1193.  
  1194. showLoadingGraphic();
  1195.  
  1196. makeGetRequest("/rpc/get_all", {}, function(response){
  1197. parseSeparatedData(response, setup, setupOrig, "=");
  1198. returnedCalls++;
  1199. if (expectedCalls == returnedCalls) {
  1200. loadSetupHtml();
  1201. hideLoadingGraphic();
  1202. }
  1203. });
  1204.  
  1205. makeGetRequest("/rpc/view_names", {}, function(response){
  1206. parseData(response, setup, setupOrig, "viewnames", ",");
  1207. returnedCalls++;
  1208. if (expectedCalls == returnedCalls) {
  1209. loadSetupHtml();
  1210. hideLoadingGraphic();
  1211. }
  1212. });
  1213. }
  1214.  
  1215. function loadSetupHtml(){
  1216. makeGetRequest("/webconfig/setup.htm", {}, function(response){
  1217. var responseHtml = $(response);
  1218. replaceStrings(responseHtml);
  1219. replaceData(responseHtml, setup, handleSetupData);
  1220. showToggleButtons(responseHtml);
  1221.  
  1222. $(".serverSettingsContentWrapper").html(responseHtml);
  1223. $("input", "#setupContainer").live("click", onEventClick);
  1224. $("input,select", "#setupContainer").live("change", onEventChange);
  1225. highlightNav($("#nav_setup"));
  1226. });
  1227. }
  1228.  
  1229. function handleSetupData(element, key, data){
  1230. switch (key) {
  1231. case "friendlyname":
  1232. element.val(data);
  1233. break;
  1234. case "language":
  1235. var matchingLanguage = $("[value=" + data + "]", element);
  1236. matchingLanguage.attr("selected", "yes");
  1237. break;
  1238. case "viewnames":
  1239. html = "";
  1240. $.each(data, function(i, value){
  1241. var selected = "";
  1242. if (setup["defaultview"] == value) {
  1243. selected = "checked";
  1244. selectedNavType = value;
  1245. }
  1246. html += '<div class="radioControlWrapper">\
  1247. <input name="viewname" id="' + value + '" ' + selected + ' type="radio" onclick="setNavType(\'' + value + '\')" />\
  1248. <div class="radioControlTextWrapper">\
  1249. <div class="radioHeader">\
  1250. ' +
  1251. getString(value) +
  1252. '\
  1253. </div>\
  1254. <div class="smallFont">\
  1255. ' +
  1256. getString(value + "caption") +
  1257. '\
  1258. </div>\
  1259. </div>\
  1260. <div class="clear">\
  1261. </div>\
  1262. </div>';
  1263. });
  1264. element.html(html);
  1265. break;
  1266. }
  1267. }
  1268.  
  1269. function setNavType(navType){
  1270. selectedNavType = navType;
  1271. }
  1272.  
  1273. function submitSetupData(){
  1274. returnedCalls = 0;
  1275. expectedCalls = 1;
  1276. hideActionButtons();
  1277. resetChanged();
  1278. var data = "";
  1279. if (setupOrig["friendlyname"] != $("#servername").val()) data += "friendlyname=" + $("#servername").val() + "\n";
  1280. var newLanguage = $("#language").val();
  1281. if (setupOrig["language"] != newLanguage) data += "language=" + newLanguage + "\n";
  1282. if (setupOrig["defaultview"] != selectedNavType) data += "defaultview=" + selectedNavType + "\n";
  1283. //var data = "friendlyname=" + $("#servername").val() + "\nlanguage=" + $("#language").val() + "\ndefaultview=" + selectedNavType + "\n";
  1284. makePostRequest("/rpc/set_all", {}, data, function(){
  1285. returnedCalls++;
  1286. if (setupOrig["language"] != newLanguage) {
  1287. setWebDavLanguage($("#language").val()); // set also the WebDav server language
  1288. setReloadSide = true;
  1289. }
  1290. finishSaving();
  1291. });
  1292. }
  1293.  
  1294. function setWebDavLanguage(lang) {
  1295. var request = loadXMLDoc("/set_language?lang="+lang,"");
  1296. }
  1297.  
  1298. // ------------------------
  1299. // sharing page
  1300. // ------------------------
  1301. function loadSharing(){
  1302. returnedCalls = 0;
  1303. expectedCalls = 3;
  1304. saveHandler = "submitSharingData();"
  1305. inputFieldClicked = false;
  1306. changesMade = false;
  1307.  
  1308. showLoadingGraphic();
  1309.  
  1310. makeGetRequest("/rpc/get_all", {}, function(response){
  1311. parseSeparatedData(response, sharing, sharingOrig, "=");
  1312. returnedCalls++;
  1313. if (expectedCalls == returnedCalls) {
  1314. loadSharingHtml();
  1315. hideLoadingGraphic();
  1316. }
  1317. });
  1318.  
  1319. makeGetRequest("/rpc/info_clients", {}, function(response){
  1320. parseData(response, sharing, sharingOrig, "clients", "\n");
  1321. returnedCalls++;
  1322. if (expectedCalls == returnedCalls) {
  1323. loadSharingHtml();
  1324. hideLoadingGraphic();
  1325. }
  1326. });
  1327.  
  1328. makeGetRequest("/rpc/info_connected_clients", {}, function(response){
  1329. parseData(response, sharing, sharingOrig, "mediareceivers", "##########\n");
  1330. returnedCalls++;
  1331. if (expectedCalls == returnedCalls) {
  1332. loadSharingHtml();
  1333. hideLoadingGraphic();
  1334. }
  1335. });
  1336. }
  1337.  
  1338. function loadSharingHtml(){
  1339. makeGetRequest("/webconfig/sharing.htm", {}, function(response){
  1340. var responseHtml = $(response);
  1341. replaceStrings(responseHtml);
  1342. replaceData(responseHtml, sharing, handleSharingData);
  1343. showToggleButtons(responseHtml);
  1344.  
  1345. $(".serverSettingsContentWrapper").html(responseHtml);
  1346. $("input", "#sharingContainer").live("click", onEventClick);
  1347. $("input,select", "#sharingContainer").live("change", onEventChange);
  1348. highlightNav($("#nav_sharing"));
  1349. updateSharing();
  1350. updateTimer = setInterval(updateSharing, updateTimerInterval);
  1351. });
  1352. }
  1353.  
  1354. function updateSharing(){
  1355. makeGetRequest("/rpc/info_connected_clients", {}, function(response){
  1356. parseData(response, sharing, "mediareceivers", "##########\n");
  1357. updateMediaReceivers($("[key=mediareceivers]"), sharing.mediareceivers)
  1358. });
  1359. }
  1360.  
  1361. function splitContentDirs(data){
  1362. var delimiter = ",[-\\+\\*][AMVPDamvpd]\\|";
  1363. var contentDirs = new Array();
  1364. var index;
  1365. while ((index = data.search(delimiter)) != -1) {
  1366. contentDirs.push(data.substring(0, index));
  1367. data = data.substring(index + 1);
  1368. }
  1369. contentDirs.push(data);
  1370. return contentDirs;
  1371. }
  1372.  
  1373. function handleSharingData(element, key, data){
  1374. switch (key) {
  1375. case "rmautoshare":
  1376. if (sharing["platform"] == "WIN32") {
  1377. element.show();
  1378. if (data > 0) {
  1379. $("input[type=checkbox]", element).attr("checked", "true");
  1380. }
  1381. }
  1382. break;
  1383. case "contentdir":
  1384. folderBrowseDialogMsg = 1;
  1385. updateSharedFolderList(element, data);
  1386. break;
  1387. case "v":
  1388. case "clientautoenable":
  1389. element.attr("checked", data > 0)
  1390. break;
  1391. case "mediareceivers":
  1392. updateMediaReceivers(element, data);
  1393. break;
  1394. }
  1395. }
  1396.  
  1397. //A utility function used during dynamic HTML generation to determine whether a dropdown option should be selected.
  1398. //mediaKey: The value of the input in question.
  1399. //compareKey: The string to compare to.
  1400. function checkSelectedMediaOption(mediaKey, compareKey){
  1401. return (mediaKey == compareKey) ? ("selected") : ("");
  1402. }
  1403.  
  1404. function checkShareBox(checkbox){
  1405. if (checkbox.is(":checked")) {
  1406. var shareBox = $(".sharedCheckbox", checkbox.parent());
  1407. shareBox.attr("checked", true);
  1408. }
  1409. }
  1410.  
  1411. function uncheckAggregationBox(checkbox){
  1412. if (!checkbox.is(":checked")) {
  1413. var aggregationBox = $(".aggregationCheckbox", checkbox.parent());
  1414. aggregationBox.attr("checked", false);
  1415. }
  1416. }
  1417.  
  1418. //Display a dialog that allows the user to browse folders on his local machine. This can't be a browser control
  1419. //because browsers only allow file selection, not folder browsing.
  1420. //rowNumber: The number of the selected folder browse row. Used to track which input the user is working with.
  1421. function showFolderBrowse(rowNumber){
  1422. showDialogOverlay(createFolderBrowseDialog, {
  1423. onstart: makeGetRequest("/rpc/dir", {
  1424. "path": ""
  1425. }, function(response){
  1426. populateDirs(response, "", "");
  1427. })
  1428. }, {
  1429. 1: {
  1430. text: getString("select"),
  1431. onclick: "selectDir('" + rowNumber + "')"
  1432. },
  1433. 2: {
  1434. text: getString("cancel"),
  1435. onclick: "hideDialogOverlay()"
  1436. }
  1437. }, "folderBrowse");
  1438. }
  1439.  
  1440. //Hide the folder selection dialog and populate an input with the user's selected directory.
  1441. //rowNumber: The number of the selected folder browse row. Used to track which input the user is working with.
  1442. function selectDir(rowNumber){
  1443. if ($("#dirPathDisplay").html()) {
  1444. $("#pathInput" + rowNumber).val($("#dirPathDisplay").html());
  1445. onEventChange();
  1446. hideDialogOverlay();
  1447. }
  1448. }
  1449.  
  1450. function createFolderBrowseDialog(){
  1451. if (folderBrowseDialogMsg == 1)
  1452. return '<div>\
  1453. <div class="boxHeader">\
  1454. <span class="titleWrapper">\
  1455. <span class="title">' + getString("selectfolder") + '</span>\
  1456. </span>\
  1457. <div class="clear" />\
  1458. </div>\
  1459. <div id="dirPathDisplay" class="dirPathDisplay"></div>\
  1460. <div id="dirDisplayContainer"></div>\
  1461. </div>';
  1462. else
  1463. return '<div>\
  1464. <div class="boxHeader">\
  1465. <span class="titleWrapper">\
  1466. <span class="title">' + getString("selectsyncfolder") + '</span>\
  1467. </span>\
  1468. <div class="clear" />\
  1469. </div>\
  1470. <div id="dirPathDisplay" class="dirPathDisplay"></div>\
  1471. <div id="dirDisplayContainer"></div>\
  1472. </div>';
  1473. }
  1474.  
  1475. //The maximum height of the directory display area before it begins scrolling, in pixels.
  1476. function getWindowHeight() {
  1477. var windowHeight = 50;
  1478. if (typeof( window.innerWidth ) == 'number' ) {
  1479. //Non-IE
  1480. windowHeight = window.innerHeight;
  1481. } else if (document.documentElement && document.documentElement.clientHeight) {
  1482. //IE 6+ in 'standards compliant mode'
  1483. windowHeight = document.documentElement.clientHeight;
  1484. } else if (document.body && document.body.clientHeight) {
  1485. //IE 4 compatible
  1486. windowHeight = document.body.clientHeight;
  1487. }
  1488. return windowHeight;
  1489. }
  1490.  
  1491. //Generate HTML to display the list of directories, along with a breadcrumb and a link for the parent directory.
  1492. //response: The data containing the directory list.
  1493. //rootPath: The path of the previous directory.
  1494. //rootId: The id of the previous directory.
  1495. function populateDirs(response, rootPath, rootId){
  1496. ($("#dirDisplayContainer")).removeClass("scroll");
  1497. $("#dirDisplayContainer").css("height", "auto");
  1498. var html = "";
  1499. var responsePieces = response.split("\n");
  1500. var platformSpecificSeparator = responsePieces[0];
  1501. var dirDisplay = $("#dirPathDisplay");
  1502. dirDisplay.attr("dirid", rootId);
  1503. dirDisplay.html(rootPath);
  1504. if (dirDisplay.attr("dirid") && rootPath && rootId) {
  1505. var lastSlash = rootPath.lastIndexOf(platformSpecificSeparator);
  1506. var lastPipe = rootId.lastIndexOf("|");
  1507. //If rootPath matches the format of a file path (e.g. C:\), parentPath is everything from the start of the string
  1508. //to the last \, beyond which is the id of the current directory.
  1509. var parentPath = (rootPath.match(/^[A-Z]:\\$/)) ? ("") : (rootPath.substring(0, lastSlash));
  1510. //If parentPath is now only a drive designation (e.g. C:), add the \ back on.
  1511. if (parentPath.match(/^[A-Z]:$/)) {
  1512. parentPath += "\\";
  1513. }
  1514. var parentId = rootId.substring(0, lastPipe);
  1515. html += '<div class="parentDirRow" onclick="getDirs(\'' + parentPath.replace(/\\/g, "\\\\") + '\', \'' + parentId + '\', \'' + platformSpecificSeparator.replace(/\\/g, "\\\\") + '\')"><span class="parentDirIcon"></span><span>' + getString("parentdir") + '</span></div>';
  1516. }
  1517. else {
  1518. html += '<div class="parentDirRow"></div>';
  1519. }
  1520. $.each(responsePieces, function(i, value){
  1521. if (value.length > 1) {
  1522.  
  1523. // directory/file id is 3+ digits long
  1524. var ii = 3;
  1525. while ((value.charAt(ii) != "D" && value.charAt(ii) != "F") && ii < value.length) {
  1526. ii = ii + 1;
  1527. }
  1528.  
  1529. var dirId = value.substring(0, ii);
  1530. var fullId = dirId;
  1531. if (rootId) {
  1532. fullId = rootId + "|" + dirId;
  1533. }
  1534.  
  1535. var dirKey = value.charAt(ii);
  1536. var dirPath = value.substring(ii + 1);
  1537. var fullPath = dirPath;
  1538.  
  1539. if (rootPath) {
  1540. var separatorChar = (rootPath.lastIndexOf(platformSpecificSeparator) != rootPath.length - 1) ? (platformSpecificSeparator) : ("");
  1541. fullPath = rootPath + separatorChar + dirPath;
  1542. }
  1543. if (dirKey == "D") {
  1544. html += '<div class="dirRow" onclick="getDirs(\'' + fullPath.replace(/\\/g, "\\\\") + '\', \'' + fullId + '\', \'' + platformSpecificSeparator.replace(/\\/g, "\\\\") + '\')"><span class="dirIcon"></span><span>' + dirPath + '</span></div>';
  1545. }
  1546. }
  1547. });
  1548. $("#dirDisplayContainer").html(html);
  1549. //If the container is too tall, add the scroll class to it to prevent it from taking up too much real estate.
  1550. var wHeight = getWindowHeight();
  1551. var dirDisplayMaxHeight = wHeight - Math.round(wHeight/2) - $("#dirPathDisplay").outerHeight() - $("#dialogButtonContainer").outerHeight();
  1552. if (parseInt($("#dirDisplayContainer").css("height")) > dirDisplayMaxHeight) {
  1553. ($("#dirDisplayContainer")).addClass("scroll");
  1554. if (dirDisplayMaxHeight < 150) dirDisplayMaxHeight = 150;
  1555. $(".scroll").css("height", dirDisplayMaxHeight);
  1556. }
  1557. else {
  1558. ($("#dirDisplayContainer")).removeClass("scroll");
  1559. }
  1560. }
  1561.  
  1562. //Get the directories under a given directory id.
  1563. //dirPath: The path of the previous directory to be used for breadcrumb navigation.
  1564. //dirId: The id to use for the new dirs call.
  1565. function getDirs(dirPath, dirId, platformSpecificSeparator){
  1566. var passId = dirId.replace(/\|/g, platformSpecificSeparator)
  1567. makeGetRequest("/rpc/dirs", {
  1568. "path": passId
  1569. }, function(response){
  1570. populateDirs(response, dirPath, dirId);
  1571. });
  1572. }
  1573.  
  1574. //Create a new shared folder row for directory browsing. Do this only if the user hasn't chosen a directory for the last
  1575. //existing row to avoid duplicate blank rows getting stacked up.
  1576. function createNewSharedFolderRow(){
  1577. if ($(".pathInput:last", "#share_folders_container").val()) {
  1578. var sharingRows = $(".sharingRowWrapper", "#share_folders_container");
  1579. //Unbind the change listener, since only the last row should be listening to add a fresh row when a value is set.
  1580. sharingRows.unbind("change");
  1581. var i = sharingRows.length;
  1582. var html = getNewSharedFolderRowHtml(i+1);
  1583. $("#share_folders_container").append(html);
  1584. }
  1585. }
  1586.  
  1587. //Get the HTML for a shared folder row.
  1588. //i: The row number. Use this to uniquely identify the row.
  1589. function getNewSharedFolderRowHtml(i){
  1590. folderBrowseDialogMsg = 1;
  1591. return '<div class="sharingRowWrapper">\
  1592. <input class="sharedCheckbox floatL" onclick="uncheckAggregationBox($(this))" type="checkbox" checked="true"/><input id="pathInput' + i + '" class="longInput pathInput floatL" type="text" onchange="createNewSharedFolderRow()" value=""/>\
  1593. <select class="contentTypeDropdown floatL">\
  1594. <option value="A">'+getString("allcontenttypes")+'</option>\
  1595. <option value="M">'+getString("music")+'</option>\
  1596. <option value="P">'+getString("photos")+'</option>\
  1597. <option value="V">'+getString("videos")+'</option>\
  1598. <option value="m">'+getString("photos")+' & '+getString("videos")+'</option>\
  1599. <option value="p">'+getString("music")+' & '+getString("videos")+'</option>\
  1600. <option value="v">'+getString("music")+' & '+getString("photos")+'</option>\
  1601. </select>\
  1602. <a class="actionbtn floatL" onclick="showFolderBrowse(' +
  1603. i +
  1604. ')" onmousedown="onButtonMouseDown(this)" onmouseup="onButtonMouseUp(this)"><span class="actionbtn_l"></span><span class="actionbtn_c">' +
  1605. getString("browse") +
  1606. '</span><span class="actionbtn_r"></span></a>\
  1607. <input id="aggCheckbox' +
  1608. i +
  1609. '" class="aggregationCheckbox floatL" onclick="checkShareBox($(this))" type="checkbox"/>' +
  1610. '<label for="aggCheckbox' +
  1611. i +
  1612. '">' +
  1613. getString("shareforagg") +
  1614. '</label>\
  1615. <div class="clear">\
  1616. </div>\
  1617. </div>';
  1618. }
  1619.  
  1620.  
  1621. // update the receiver list and the aggregation server list
  1622. function updateMediaReceivers(element, data){
  1623. // if user has made changes, do not update the receiver and aggregation server list
  1624. if (sharingReceiverChanged) return;
  1625. if (!data) {
  1626. element.hide();
  1627. elementa.hide();
  1628. return;
  1629. }
  1630. data.pop(); //delete last element
  1631. // count the number of receivers and aggregation server
  1632. var mrec = 0;
  1633. var aggs = 0;
  1634. for (var key in data) {
  1635. var p = data[key].split("\n");
  1636. if (p[3] == 0) mrec ++;
  1637. else aggs ++;
  1638. }
  1639. // media receivers list
  1640. var html = "";
  1641. // set header if there are receivers
  1642. if (mrec > 0) {
  1643. html = '<tr>\
  1644. <th>\
  1645. </th>\
  1646. <th>\
  1647. <span>' + getString("mac") + '</span>\
  1648. </th>\
  1649. <th>\
  1650. <span>' +
  1651. getString("ip") +
  1652. '</span>\
  1653. </th>\
  1654. <th>\
  1655. <span>' +
  1656. getString("friendlyname") +
  1657. '</span>\
  1658. </th>\
  1659. <th>\
  1660. <span>' +
  1661. getString("receivertype") +
  1662. '</span>\
  1663. </th>\
  1664. <th>\
  1665. <span>' +
  1666. getString("navtype") +
  1667. '</span>\
  1668. </th>\
  1669. </tr>';
  1670. }
  1671. // aggregation server list
  1672. var elementa = $("[key=aggservers]");
  1673. var htmla = "";
  1674. // set header if there are aggregation server
  1675. if (aggs > 0) {
  1676. htmla = '<tr>\
  1677. <th>\
  1678. <span>' + getString("mac") + '</span>\
  1679. </th>\
  1680. <th>\
  1681. <span>' +
  1682. getString("ip") +
  1683. '</span>\
  1684. </th>\
  1685. <th>\
  1686. <span>' +
  1687. getString("friendlyname") +
  1688. '</span>\
  1689. </th>\
  1690. </tr>';
  1691. }
  1692. $.each(data, function(i, value){
  1693. var receiverPieces = value.split("\n");
  1694. var receiver = {};
  1695. receiver["id"] = receiverPieces[0];
  1696. receiver["mac"] = receiverPieces[1];
  1697. receiver["ip"] = receiverPieces[2];
  1698. receiver["isAggregation"] = receiverPieces[3];
  1699. receiver["enabled"] = receiverPieces[4];
  1700. receiver["clientName"] = receiverPieces[5];
  1701. receiver["icon"] = receiverPieces[6];
  1702. receiver["iconMimeType"] = receiverPieces[7];
  1703. receiver["viewName"] = receiverPieces[8];
  1704. receiver["hasDefaultView"] = receiverPieces[9];
  1705. receiver["friendlyname"] = receiverPieces[10];
  1706. var checked = (receiver.enabled == 1) ? ("checked") : ("");
  1707. if (receiver.isAggregation == 0) {
  1708. html += '<tr id="receiverRow' + i + '">\
  1709. <td>\
  1710. <input onchange="receiverChanged(' +
  1711. i +
  1712. ')" type="checkbox" ' +
  1713. checked +
  1714. '/>\
  1715. </td>\
  1716. <td>\
  1717. <input class="macInput" type="text" value="' +
  1718. receiver.mac +
  1719. '" disabled="true" style="cursor:default" />\
  1720. </td>\
  1721. <td>\
  1722. <input class="ipInput" type="text" value="' +
  1723. receiver.ip +
  1724. '" disabled="true" style="cursor:default" />\
  1725. </td>\
  1726. <td>\
  1727. <input class="fnameInput" type="text" value="' +
  1728. receiver.friendlyname +
  1729. '" disabled="true" title="' + receiver.friendlyname + '" alt="' + receiver.friendlyname + '" style="cursor:default" />\
  1730. </td>\
  1731. <td>' +
  1732. getReceiverClientDropdown(receiver.clientName, i) +
  1733. '</td>\
  1734. <td>' +
  1735. getReceiverViewDropdown(receiver.viewName, receiver.hasDefaultView == 1, i) +
  1736. '</td>\
  1737. </tr>';
  1738. } else {
  1739. htmla += '<tr id="aggserverRow' + i + '">\
  1740. <td>\
  1741. <input class="macInput" type="text" value="' +
  1742. receiver.mac +
  1743. '" disabled="true" style="cursor:default" />\
  1744. </td>\
  1745. <td>\
  1746. <input class="ipInput" type="text" value="' +
  1747. receiver.ip +
  1748. '" disabled="true" style="cursor:default" />\
  1749. </td>\
  1750. <td>\
  1751. <input class="fnameInput" type="text" value="' +
  1752. receiver.friendlyname +
  1753. '" disabled="true" title="' + receiver.friendlyname + '" alt="' + receiver.friendlyname + '" style="cursor:default" />\
  1754. </td>\
  1755. </tr>';
  1756. }
  1757. });
  1758. element.html("");
  1759. element.show();
  1760. element.append(html);
  1761. elementa.html("");
  1762. elementa.show();
  1763. elementa.append(htmla);
  1764. }
  1765. function updateSharedFolderList(element, data){
  1766. // shared folder list
  1767. element.html("");
  1768. var html = "";
  1769. var dirPairs = splitContentDirs(data);
  1770. var html = "";
  1771. if ((dirPairs.length == 1) && (dirPairs[0] == "")) {
  1772. element.append(getNewSharedFolderRowHtml(dirPairs.length));
  1773. return;
  1774. }
  1775. // list the content dirs
  1776. $.each(dirPairs, function(i, value){
  1777. var dirPieces = value.split("|");
  1778. var dirPath = dirPieces[1];
  1779. var dirKeys = dirPieces[0];
  1780. var enabledKey = dirKeys.substring(0, 1);
  1781. var mediaKey = dirKeys.substring(1, 2);
  1782. var shared = (enabledKey == "+" || enabledKey == "*") ? ("checked") : ("");
  1783. var enabledForAgg = (enabledKey == "*") ? ("checked") : ("");
  1784. html += '<div class="sharingRowWrapper">\
  1785. <input class="sharedCheckbox floatL" onclick="uncheckAggregationBox($(this))" type="checkbox" ' + shared + '/><input id="pathInput' + i + '" class="longInput pathInput floatL" type="text" value="' + dirPath + '"/>\
  1786. <select class="contentTypeDropdown floatL">\
  1787. <option value="A" ' +
  1788. checkSelectedMediaOption(mediaKey, "A") +
  1789. '>'+getString("allcontenttypes")+'</option>\
  1790. <option value="M" ' +
  1791. checkSelectedMediaOption(mediaKey, "M") +
  1792. '>'+getString("music")+'</option>\
  1793. <option value="P" ' +
  1794. checkSelectedMediaOption(mediaKey, "P") +
  1795. '>'+getString("photos")+'</option>\
  1796. <option value="V" ' +
  1797. checkSelectedMediaOption(mediaKey, "V") +
  1798. '>'+getString("videos")+'</option>\
  1799. <option value="m" ' +
  1800. checkSelectedMediaOption(mediaKey, "m") +
  1801. '>'+getString("photos")+' & '+getString("videos")+'</option>\
  1802. <option value="p" ' +
  1803. checkSelectedMediaOption(mediaKey, "p") +
  1804. '>'+getString("music")+' & '+getString("videos")+'</option>\
  1805. <option value="v" ' +
  1806. checkSelectedMediaOption(mediaKey, "v") +
  1807. '>'+getString("music")+' & '+getString("photos")+'</option>\
  1808. </select>\
  1809. <a class="actionbtn floatL" onclick="showFolderBrowse(' +
  1810. i +
  1811. ')" onmousedown="onButtonMouseDown(this)" onmouseup="onButtonMouseUp(this)"><span class="actionbtn_l"></span><span class="actionbtn_c">' +
  1812. getString("browse") +
  1813. '</span><span class="actionbtn_r"></span></a>\
  1814. <input id="aggCheckbox' +
  1815. i +
  1816. '" class="aggregationCheckbox floatL" onclick="checkShareBox($(this))" type="checkbox" ' +
  1817. enabledForAgg +
  1818. '/>' +
  1819. '<label for="aggCheckbox' +
  1820. i +
  1821. '">' +
  1822. getString("shareforagg") +
  1823. '</label>\
  1824. <div class="clear">\
  1825. </div>\
  1826. </div>';
  1827. });
  1828. element.html(html);
  1829. element.append(getNewSharedFolderRowHtml(dirPairs.length + 1));
  1830. }
  1831.  
  1832. function submitSharingData(){
  1833. var args = submitSharingData.arguments.length;
  1834. returnedCalls = 0;
  1835. expectedCalls = 1;
  1836. showLoadingGraphic();
  1837. hideActionButtons();
  1838. resetChanged();
  1839. //Only submit client_add requests for receivers that have been changed.
  1840. sharingReceiverChanged = false;
  1841. $.each(changedReceivers, function(key, receiverRow){
  1842. expectedCalls++;
  1843. var enabled = ($("input[type=checkbox]", receiverRow).attr("checked")) ? ("1") : ("0");
  1844. var clientId = $("select[name=clientType]", receiverRow).val();
  1845. var viewName = $("select[name=viewName]", receiverRow).val();
  1846. var mac = $(".macInput", receiverRow).val();
  1847. makeGetRequest("/rpc/client_add", {
  1848. "mac": mac,
  1849. "id": clientId,
  1850. "enabled": enabled,
  1851. "view": viewName
  1852. }, function(){
  1853. returnedCalls++;
  1854. finishSaving();
  1855. });
  1856. });
  1857.  
  1858. var shareFoldersList = $(".sharingRowWrapper", $("#share_folders_container"));
  1859. var emptyPath = false;
  1860. var contentDirKey = "contentdir=";
  1861. var contentDir = "contentdir=";
  1862. $.each(shareFoldersList, function(i, value){
  1863. var dirInput = $(".pathInput", value);
  1864. var dirPath = dirInput.val();
  1865. if (dirPath) {
  1866. var sharedCheckbox = $(".sharedCheckbox", value);
  1867. var aggregationCheckbox = $(".aggregationCheckbox", value);
  1868. var enabledKey;
  1869. if (sharedCheckbox.is(":checked") && aggregationCheckbox.is(":checked")) {
  1870. enabledKey = "*";
  1871. }
  1872. else
  1873. if (sharedCheckbox.is(":checked")) {
  1874. enabledKey = "+";
  1875. }
  1876. else {
  1877. enabledKey = "-";
  1878. }
  1879. var mediaKey = $(".contentTypeDropdown", value).val();
  1880. contentDir += enabledKey + mediaKey + "|" + dirPath + ",";
  1881. }
  1882. else emptyPath = true;
  1883. });
  1884. if (contentDir.length > contentDirKey.length) contentDir = contentDir.substring(0, contentDir.length - 1);
  1885. var data = "";
  1886. data += contentDir + "\n";
  1887. var autoshareCheckbox = $("#autoshareCheckbox", $(".serverSettingsContentWrapper"));
  1888. var autoshareCheckboxValue = ((autoshareCheckbox.is(":checked")) ? (1) : (0));
  1889. if (sharingOrig["rmautoshare"] != autoshareCheckboxValue) data += "rmautoshare=" + autoshareCheckboxValue + "\n";
  1890. var clientautoenable = (($("input[key=clientautoenable]").attr("checked") == true) ? ("1") : ("0"));
  1891. if (sharingOrig["clientautoenable"] != clientautoenable) data += "clientautoenable=" + clientautoenable + "\n";
  1892. //var data = contentDir + "\n" + autoshareRmEnabled + "\n" + clientautoenable + "\n";
  1893. makePostRequest("/rpc/set_all", {}, data, function(){
  1894. returnedCalls++;
  1895. finishSaving();
  1896. hideLoadingGraphic();
  1897. if ((args > 0) && emptyPath) {
  1898. updateSharedFolderList($("[key=contentdir]"), contentDir.substring(contentDirKey.length, contentDir.length))
  1899. }
  1900. });
  1901. }
  1902.  
  1903.  
  1904. // ------------------------
  1905. // aggregation page
  1906. // ------------------------
  1907. function loadAggregation(){
  1908. returnedCalls = 0;
  1909. expectedCalls = 2;
  1910. saveHandler = "submitAggregationData();"
  1911. inputFieldClicked = false;
  1912. changesMade = false;
  1913.  
  1914. showLoadingGraphic();
  1915.  
  1916. makeGetRequest("/rpc/get_all", {}, function(response){
  1917. parseSeparatedData(response, aggregation, aggregationOrig, "=");
  1918. returnedCalls++;
  1919. if (expectedCalls == returnedCalls) {
  1920. loadAggregationHtml();
  1921. hideLoadingGraphic();
  1922. }
  1923. });
  1924.  
  1925. //The listaggregatedservers call will fail if aggregation is disabled. If data is returned, handle it as normal.
  1926. //Otherwise, make sure the aggregated servers collection is empty and load the HTML.
  1927. $.ajax("/rpc/listaggregatedservers", {
  1928. success: function(response){
  1929. parseData(response, aggregation, aggregationOrig, "aggregatedservers", "--");
  1930. returnedCalls++;
  1931. if (expectedCalls == returnedCalls) {
  1932. loadAggregationHtml();
  1933. hideLoadingGraphic();
  1934. }
  1935. },
  1936. error: function(){
  1937. aggregation["aggregatedservers"] = null;
  1938. returnedCalls++;
  1939. if (expectedCalls == returnedCalls) {
  1940. loadAggregationHtml();
  1941. hideLoadingGraphic();
  1942. }
  1943. }
  1944. });
  1945. }
  1946.  
  1947. function loadAggregationHtml(){
  1948. makeGetRequest("/webconfig/aggregation.htm", {}, function(response){
  1949. var responseHtml = $(response);
  1950. replaceStrings(responseHtml);
  1951. replaceData(responseHtml, aggregation, handleAggregationData);
  1952. showToggleButtons(responseHtml);
  1953.  
  1954. $(".serverSettingsContentWrapper").html(responseHtml);
  1955. //Show or hide the aggregation server container based on whether or not aggregation is enabled.
  1956. toggleAvailableServers(aggregation["aggregation"] == 1);
  1957. $("input,select", "#aggregationContainer").live("change", onEventChange);
  1958. highlightNav($("#nav_aggregation"));
  1959. updateTimer = setInterval(updateAggregation, updateTimerInterval);
  1960. });
  1961. }
  1962.  
  1963. function updateAggregation(){
  1964. //Only call to get an updated list of servers if no changes have been made. This avoids
  1965. // updating HTML while a user is making changes.
  1966. if(!changesMade) {
  1967. $.ajax("/rpc/listaggregatedservers", {
  1968. success: function(response){
  1969. parseData(response, aggregation, aggregationOrig, "aggregatedservers", "--");
  1970. updateAggregatedServers($("[key=aggregatedservers]"), aggregation.aggregatedservers);
  1971. },
  1972. error: function(){
  1973. aggregation["aggregatedservers"] = null;
  1974. }
  1975. });
  1976. }
  1977. }
  1978.  
  1979. function handleAggregationData(element, key, data){
  1980. switch (key) {
  1981. case "aggregation":
  1982. if (data == 1) {
  1983. element.attr("checked", true);
  1984. }
  1985. break;
  1986. case "aggmode":
  1987. var matchingInput = $("input[type=radio][name=aggregationMode][value=" + data + "]", element);
  1988. matchingInput.attr("checked", true);
  1989. break;
  1990. case "aggregatedservers":
  1991. updateAggregatedServers(element, data);
  1992. break;
  1993. }
  1994. }
  1995.  
  1996. function updateAggregatedServers(element, data){
  1997. if (data) {
  1998. var serverHtml = "";
  1999. //Pop the last element of the collection off, since it's an empty piece of data.
  2000. data.pop();
  2001. $.each(data, function(i, value){
  2002. var serverDataPieces = value.split("<br>");
  2003. var serverData = {};
  2004. $.each(serverDataPieces, function(i, value){
  2005. var dataKey = value.substring(0, 1);
  2006. var dataValue = value.substring(2, value.length).replace(/\n/g, "");
  2007. serverData[dataKey] = dataValue;
  2008. });
  2009. var musicChecked = "";
  2010. var photosChecked = "";
  2011. var videosChecked = "";
  2012. switch (serverData["F"]) {
  2013. case "A":
  2014. musicChecked = "checked";
  2015. photosChecked = "checked";
  2016. videosChecked = "checked";
  2017. break;
  2018. case "M":
  2019. musicChecked = "checked";
  2020. break;
  2021. case "P":
  2022. photosChecked = "checked";
  2023. break;
  2024. case "V":
  2025. videosChecked = "checked";
  2026. break;
  2027. case "m":
  2028. photosChecked = "checked";
  2029. videosChecked = "checked";
  2030. break;
  2031. case "p":
  2032. musicChecked = "checked";
  2033. videosChecked = "checked";
  2034. break;
  2035. case "v":
  2036. musicChecked = "checked";
  2037. photosChecked = "checked";
  2038. break;
  2039. }
  2040.  
  2041. serverHtml += '<div uuid="' + serverData["S"] + '" class="availableServerContainer">' +
  2042. serverData["N"] +
  2043. '<div>\
  2044. <span class="serverMediaLabel"><input onclick="onServerChanged(\'' +
  2045. serverData["S"] +
  2046. '\')" name="songs" type="checkbox"' +
  2047. musicChecked +
  2048. '/>' +
  2049. getString("songs") +
  2050. ' ' +
  2051. serverData["M"] +
  2052. '</span><span class="serverMediaLabel"><input onclick="onServerChanged(\'' +
  2053. serverData["S"] +
  2054. '\')" name="photos" type="checkbox"' +
  2055. photosChecked +
  2056. '/>' +
  2057. getString("photos") +
  2058. ' ' +
  2059. serverData["P"] +
  2060. '</span><span class="serverMediaLabel"><input onclick="onServerChanged(\'' +
  2061. serverData["S"] +
  2062. '\')" name="videos" type="checkbox"' +
  2063. videosChecked +
  2064. '/>' +
  2065. getString("videos") +
  2066. ' ' +
  2067. serverData["V"] +
  2068. '</span>\
  2069. </div>\
  2070. <div class="radioControlWrapper">\
  2071. <input onclick="onServerChanged(\'' +
  2072. serverData["S"] +
  2073. '\')" name="' +
  2074. serverData["S"] +
  2075. 'aggmode" type="radio" ' +
  2076. checkAggMode(0, serverData["E"]) +
  2077. ' value="0" />\
  2078. <div class="radioControlTextWrapper nocaption">\
  2079. <div class="radioHeader">' +
  2080. getString("ignore") +
  2081. '</div>\
  2082. </div>\
  2083. <div class="clear">\
  2084. </div>\
  2085. </div>\
  2086. <div class="radioControlWrapper">\
  2087. <input onclick="onServerChanged(\'' +
  2088. serverData["S"] +
  2089. '\')" name="' +
  2090. serverData["S"] +
  2091. 'aggmode" type="radio" ' +
  2092. checkAggMode(1, serverData["E"]) +
  2093. ' value="1" />\
  2094. <div class="radioControlTextWrapper nocaption">\
  2095. <div class="radioHeader">' +
  2096. getString("aggregate") +
  2097. '</div>\
  2098. </div>\
  2099. <div class="clear">\
  2100. </div>\
  2101. </div>\
  2102. <div class="radioControlWrapper">\
  2103. <input onclick="onServerChanged(\'' +
  2104. serverData["S"] +
  2105. '\')" name="' +
  2106. serverData["S"] +
  2107. 'aggmode" type="radio" ' +
  2108. checkAggMode(2, serverData["E"]) +
  2109. ' value="2" />\
  2110. <div class="radioControlTextWrapper nocaption">\
  2111. <div class="radioHeader">' +
  2112. getString("mirror") +
  2113. '</div>\
  2114. </div>\
  2115. <div class="clear">\
  2116. </div>\
  2117. </div>\
  2118. </div>';
  2119. });
  2120. element.show();
  2121. element.html(serverHtml);
  2122. }
  2123. else {
  2124. element.hide();
  2125. }
  2126. }
  2127.  
  2128. //A utility function to determine whether a checkbox or radio input should be checked.
  2129. //aggMode: The value of the input in question.
  2130. //compareMode: The string to compare to.
  2131. function checkAggMode(aggMode, compareMode){
  2132. return (aggMode == compareMode) ? ("checked") : ("");
  2133. }
  2134.  
  2135. //When a server is updated, add it to the changedServers collection.
  2136. //uuid: The uuid of the changed server.
  2137. function onServerChanged(uuid){
  2138. changedServers[uuid] = uuid;
  2139. }
  2140.  
  2141. function toggleAvailableServers(isAggEnabled){
  2142. (isAggEnabled) ? ($("#availableServersContainer").show()) : ($("#availableServersContainer").hide());
  2143. }
  2144.  
  2145. function submitAggregationData(){
  2146. hideActionButtons();
  2147. returnedCalls = 0;
  2148. expectedCalls = 1;
  2149.  
  2150. showLoadingGraphic();
  2151. resetChanged();
  2152.  
  2153. var aggregationEnabledCheckbox = $("#aggregationEnabledCheckbox");
  2154. var enableAggregation = ((aggregationEnabledCheckbox.is(":checked")) ? (1) : (0));
  2155. var aggMode = $("input[name=aggregationMode]:checked").val();
  2156. //var data = enableAggregation + "\n" + aggMode + "\n";
  2157. var data = "";
  2158. if (aggregationOrig["aggregation"] != enableAggregation) data += "aggregation=" + enableAggregation + "\n";
  2159. if (aggregationOrig["aggmode"] != aggMode) data += "aggmode=" + aggMode + "\n";
  2160.  
  2161. var aggregationServers = $(".availableServerContainer");
  2162. $.each(aggregationServers, function(i, value){
  2163. var element = $(value);
  2164. //Only submit aggregatedserverswitch and aggregatedservercontent calls for servers that have been changed
  2165. //(are in the changedServers collection).
  2166. if (changedServers[element.attr("uuid")]) {
  2167. expectedCalls += 2;
  2168. var selectedAggregationMode = $("input[type=radio]:checked", element).val();
  2169. var selectedContentTypes = $("input[type=checkbox]:checked", element);
  2170. var musicChecked = false;
  2171. var photosChecked = false;
  2172. var videosChecked = false;
  2173. $.each(selectedContentTypes, function(i, value){
  2174. var checkbox = $(value);
  2175. switch (checkbox.attr("name")) {
  2176. case "songs":
  2177. musicChecked = true;
  2178. break;
  2179. case "photos":
  2180. photosChecked = true;
  2181. break;
  2182. case "videos":
  2183. videosChecked = true;
  2184. break;
  2185. }
  2186. });
  2187. var contentType = "";
  2188. if (musicChecked && photosChecked && videosChecked) {
  2189. contentType = "A";
  2190. }
  2191. else
  2192. if (musicChecked && photosChecked) {
  2193. contentType = "v";
  2194. }
  2195. else
  2196. if (musicChecked && videosChecked) {
  2197. contentType = "p";
  2198. }
  2199. else
  2200. if (photosChecked && videosChecked) {
  2201. contentType = "m";
  2202. }
  2203. else
  2204. if (musicChecked) {
  2205. contentType = "M";
  2206. }
  2207. else
  2208. if (photosChecked) {
  2209. contentType = "P";
  2210. }
  2211. else
  2212. if (videosChecked) {
  2213. contentType = "V";
  2214. }
  2215. makeGetRequest("/rpc/aggregatedserverswitch", {
  2216. "uuid": element.attr("uuid"),
  2217. "enabled": selectedAggregationMode
  2218. }, function(){
  2219. returnedCalls++;
  2220. finishSaving();
  2221. });
  2222. makeGetRequest("/rpc/aggregatedservercontent", {
  2223. "uuid": element.attr("uuid"),
  2224. "cType": contentType
  2225. }, function(){
  2226. returnedCalls++;
  2227. finishSaving();
  2228. });
  2229. }
  2230. });
  2231. makePostRequest("/rpc/set_all", {}, data, function(){
  2232. returnedCalls++;
  2233. finishSaving();
  2234. hideLoadingGraphic();
  2235. });
  2236. }
  2237.  
  2238. function finishSaving(){
  2239. if (returnedCalls == expectedCalls) {
  2240. showActionButtons();
  2241. makeGetRequest("/rpc/info_status", {}, function(data){
  2242. var dataPieces = data.split("\n");
  2243. $.each(dataPieces, function(i, value){
  2244. var pieces = value.split("|");
  2245. if (pieces[0] == "restartpending") {
  2246. var restartPending = (pieces[1] == 1);
  2247. if (restartPending) {
  2248. showDialogOverlay(function(){
  2249. return getString("restartprompt")
  2250. }, {}, [{
  2251. text: getString("ok"),
  2252. onclick: "restartServer();"
  2253. }, {
  2254. text: getString("cancel"),
  2255. onclick: "hideDialogOverlay();"
  2256. }]);
  2257. }
  2258. return false;
  2259. }
  2260. });
  2261. });
  2262. }
  2263. }
  2264.  
  2265.  
  2266. // ------------------------
  2267. // advanced page
  2268. // ------------------------
  2269. function loadAdvanced(){
  2270. returnedCalls = 0;
  2271. expectedCalls = 6;
  2272. saveHandler = "submitAdvancedData();"
  2273. inputFieldClicked = false;
  2274. changesMade = false;
  2275.  
  2276. showLoadingGraphic();
  2277.  
  2278. // function get_server_type restored - should be retired again.
  2279. makeGetRequest("/rpc/get_server_type", {}, function(response){
  2280. advanced["servertype"] = response;
  2281. returnedCalls++;
  2282. if (expectedCalls == returnedCalls) {
  2283. loadAdvancedHtml();
  2284. hideLoadingGraphic();
  2285. }
  2286. });
  2287.  
  2288. makeGetRequest("/rpc/get_all", {}, function(response){
  2289. parseSeparatedData(response, advanced, advancedOrig, "=");
  2290. returnedCalls++;
  2291. if (expectedCalls == returnedCalls) {
  2292. loadAdvancedHtml();
  2293. hideLoadingGraphic();
  2294. }
  2295. });
  2296.  
  2297. makeGetRequest("/rpc/info_status", {}, function(response){
  2298. parseSeparatedData(response, advanced, advancedOrig, "|");
  2299. // advanced["servertype"] = getServerType(advanced["licensestatus"]);
  2300. returnedCalls++;
  2301. if (expectedCalls == returnedCalls) {
  2302. loadAdvancedHtml();
  2303. hideLoadingGraphic();
  2304. }
  2305. });
  2306.  
  2307. makeGetRequest("/rpc/get_portal_info", {}, function(response){
  2308. advanced["portalinfo"] = response;
  2309. returnedCalls++;
  2310. if (expectedCalls == returnedCalls) {
  2311. loadAdvancedHtml();
  2312. hideLoadingGraphic();
  2313. }
  2314. });
  2315.  
  2316. makeGetRequest("/rpc/get_option?portalusername", {}, function(response){
  2317. advanced["portalusername"] = response;
  2318. returnedCalls++;
  2319. if (expectedCalls == returnedCalls) {
  2320. loadAdvancedHtml();
  2321. hideLoadingGraphic();
  2322. }
  2323. });
  2324.  
  2325. makeGetRequest("/rpc/get_webdav_link", {}, function(response){
  2326. parseData(response, advanced, advancedOrig, "webdavLink", "\n");
  2327. returnedCalls++;
  2328. if (expectedCalls == returnedCalls) {
  2329. loadAdvancedHtml();
  2330. hideLoadingGraphic();
  2331. }
  2332. });
  2333. }
  2334.  
  2335. function loadAdvancedHtml(){
  2336. makeGetRequest("/webconfig/advanced.htm", {}, function(response){
  2337. var responseHtml = $(response);
  2338. replaceStrings(responseHtml);
  2339. replaceData(responseHtml, advanced, handleAdvancedData);
  2340. showToggleButtons(responseHtml);
  2341.  
  2342. $(".serverSettingsContentWrapper").html(responseHtml);
  2343. hideWebdavContainer(advanced["webdavLink"]);
  2344. $("input", "#advancedContainer").live("click", onEventClick);
  2345. $("input,select", "#advancedContainer").live("change", onEventChange);
  2346. highlightNav($("#nav_advanced"));
  2347. });
  2348. }
  2349.  
  2350. function hideWebdavContainer(data){
  2351. if (data[0].toLowerCase() == "nowebdav") {
  2352. ($("#availableWebdavContainer").hide());
  2353. } else {
  2354. ($("#availableWebdavContainer").show());
  2355. }
  2356. }
  2357.  
  2358. function handleAdvancedData(element, key, data){
  2359. var serverType = advanced["servertype"];
  2360. switch (key) {
  2361. case "accessuser":
  2362. element.val(data);
  2363. break;
  2364. case "accesspwd":
  2365. if (data.length > 0) element.val("_twonkypassword_");
  2366. break;
  2367. case "myexperience":
  2368. // Do not show the header "Improve My Experience" if it is the free server
  2369. if (serverType.toLowerCase().lastIndexOf("free") > -1) break;
  2370. // Do not show the header "Improve My Experience" if it is a server with license key
  2371. if ((advanced["licensestatus"] >= 2) && (advanced["cdkey"].length > 1)) break;
  2372. // show this header if it is an OEM server
  2373. if (advanced["reportdevice"])
  2374. element.show();
  2375. break;
  2376. case "reportdevice":
  2377. element.attr("checked", data > 0)
  2378. break;
  2379. case "compilationsdir":
  2380. case "scantime":
  2381. element.val(data);
  2382. break;
  2383. case "nicrestart":
  2384. element.attr("checked", data > 0)
  2385. break;
  2386. case "v":
  2387. element.attr("checked", data > 0)
  2388. break;
  2389. case "webdavLink":
  2390. element.attr("href", data);
  2391. break;
  2392. case "portaldisassociation":
  2393. if (noMediaFusionServer || myTwonkyDisabled) break;
  2394. if ((advanced["portalinfo"] != "useronline") && (advanced["portalinfo"] != "notloggedin")) break;
  2395. element.show();
  2396. break;
  2397. case "portalinfo":
  2398. if (noMediaFusionServer || myTwonkyDisabled) break;
  2399. if ((data != "useronline") && (data != "notloggedin")) break;
  2400. var renewStr = "";
  2401. var serverTypeShort = "premium";
  2402. if (serverType.toLowerCase().lastIndexOf("free") > -1) {
  2403. serverTypeShort = "free";
  2404. }
  2405. var disLink = '<div><a class="actionbtnmd bold" onmousedown="onButtonMouseDown(this)" onmouseup="onButtonMouseUp(this)"\
  2406. onclick="disassociatePortalLink(\'' + serverTypeShort + '\')"><span class="actionbtn_l"></span><span class="actionbtn_c">' +
  2407. getString("portaldisassociate") +
  2408. '</span><span class="actionbtn_r"></span></a></div>';
  2409. switch (data) {
  2410. case "useronline":
  2411. returnValue = getString("loggedinas") + " " + advanced["portalusername"] + '<br /><br />' + disLink + '<div class="serverContentSpacer"></div>';
  2412. element.html(returnValue);
  2413. break;
  2414. case "notloggedin":
  2415. returnValue = getString("loginneededcaption") + '<br /><br />' + disLink + '<div class="serverContentSpacer"></div>';
  2416. element.html(returnValue);
  2417. break;
  2418. }
  2419. }
  2420. }
  2421.  
  2422.  
  2423.  
  2424.  
  2425. //Get HTML for the receiver navigation view dropdown.
  2426. //selectedView: The currently selected navigation view for the current receiver.
  2427. //isDefault: A boolean that indicates whether or not the user is able to update the dropdown. If true, a disabled
  2428. //dropdown is returned.
  2429. //i: The row number used to uniquely identify the receiver.
  2430. function getReceiverViewDropdown(selectedView, isDefault, i){
  2431. var html = "";
  2432. if (!isDefault) {
  2433. html = '<select name="viewName" onchange="receiverChanged(' + i + ')">\
  2434. <option value="mobile" ' +
  2435. checkSelectedMediaOption("mobile", selectedView) +
  2436. '>' +
  2437. getString("mobile") +
  2438. '</option>\
  2439. <option value="simpledefault" ' +
  2440. checkSelectedMediaOption("simpledefault", selectedView) +
  2441. '>' +
  2442. getString("simpledefault") +
  2443. '</option>\
  2444. <option value="ipodlike" ' +
  2445. checkSelectedMediaOption("ipodlike", selectedView) +
  2446. '>' +
  2447. getString("ipodlike") +
  2448. '</option>\
  2449. <option value="byfolder" ' +
  2450. checkSelectedMediaOption("byfolder", selectedView) +
  2451. '>' +
  2452. getString("byfolder") +
  2453. '</option>\
  2454. <option value="advanceddefault" ' +
  2455. checkSelectedMediaOption("advanceddefault", selectedView) +
  2456. '>' +
  2457. getString("advanceddefault") +
  2458. '</option>\
  2459. </select>';
  2460. }
  2461. else {
  2462. html = '';
  2463. }
  2464. return html;
  2465. }
  2466.  
  2467. //Get HTML for the receiver client type dropdown.
  2468. //selectedView: The currently selected navigation view for the current receiver.
  2469. //i: The row number used to uniquely identify the receiver.
  2470. function getReceiverClientDropdown(selectedClient, i){
  2471. var html = '<select class="clientType" name="clientType" onchange="receiverChanged(' + i + ')">';
  2472. var clientPieces = sharing.clients[0].split(",");
  2473. $.each(clientPieces, function(i, value){
  2474. if (i % 2 == 0) {
  2475. html += '<option value="' + value + '" ';
  2476. }
  2477. else {
  2478. html += checkSelectedMediaOption(value, selectedClient) + '>' + value + '</option>';
  2479. }
  2480. });
  2481. html += "</select>";
  2482. return html;
  2483. }
  2484.  
  2485. //Add a changed receiver to the changedReceviers collection.
  2486. //i: The row number of the changed receiver.
  2487. function receiverChanged(i){
  2488. sharingReceiverChanged = true;
  2489. changedReceivers[i] = $("#receiverRow" + i, ".mediaReceiversTable");
  2490. }
  2491.  
  2492. function clearPassword() {
  2493. $("#password").val("");
  2494. }
  2495.  
  2496. function submitAdvancedData(){
  2497. var accessCredentialChanged = false;
  2498. hideActionButtons();
  2499. returnedCalls = 0;
  2500. expectedCalls = 1;
  2501.  
  2502. showLoadingGraphic();
  2503. resetChanged();
  2504.  
  2505. var compilations = $("#compilations", ".accountSettingsContainer").val();
  2506. var rescan = $("#rescan", ".accountSettingsContainer").val();
  2507. var nicrestart = (($("#nicRestartEnabledCheckbox").attr("checked") == true) ? ("1") : ("0"));
  2508. var myexperience = (($("#myExperienceEnabledCheckbox").attr("checked") == true) ? ("1") : ("0"));
  2509. var loggingEnabled = (($("#loggingEnabledCheckbox").attr("checked") == true) ? ("4095") : ("0"));
  2510. var data = "";
  2511. if (advancedOrig["compilationsdir"] != compilations) data += "compilationsdir=" + compilations + "\n";
  2512. if (advancedOrig["scantime"] != rescan) data += "scantime=" + rescan + "\n";
  2513. if (advancedOrig["nicrestart"] != nicrestart) data += "nicrestart=" + nicrestart + "\n";
  2514. if (advancedOrig["myexperience"] != myexperience) data += "reportdevice=" + myexperience + "\n";
  2515. if (advancedOrig["v"] != loggingEnabled) data += "v=" + loggingEnabled + "\n";
  2516.  
  2517. if (!($("#password", ".accountSettingsContainer").val() == "_twonkypassword_")) {
  2518. var username = "accessuser=" + $("#username", ".accountSettingsContainer").val();
  2519. var password = "accesspwd=" + $("#password", ".accountSettingsContainer").val();
  2520. if (((username.length > 11) && (password.length > 10)) || ((username.length == 11) && (password.length == 10))) {
  2521. // set new username password
  2522. data += username + "\n" + password + "\n";
  2523. accessCredentialChanged = true;
  2524. } else {
  2525. // reset username and password (only username or password was entered)
  2526. $("#username").val(advancedOrig["accessuser"]);
  2527. if (advancedOrig["accesspwd"].length > 0) $("#password").val("_twonkypassword_");
  2528. else $("#password").val("");
  2529. showDialogOverlay(function(){
  2530. return getString("notchanged")
  2531. }, {}, [{
  2532. text: getString("ok"),
  2533. onclick: "hideDialogOverlay();"
  2534. }]);
  2535. }
  2536. }
  2537. makePostRequest("/rpc/set_all", {}, data, function(){
  2538. returnedCalls++;
  2539. finishSaving();
  2540. hideLoadingGraphic();
  2541. //Refresh the page if the user has changed the username or password to make sure the user is prompted correctly.
  2542. //if ($("#username", ".accountSettingsContainer").val() != advanced["accessuser"] || $("#password", ".accountSettingsContainer").val() != advanced["accesspwd"]) {
  2543. if (accessCredentialChanged) {
  2544. updateWebDavAdmin($("#username", ".accountSettingsContainer").val(), $("#password", ".accountSettingsContainer").val()); // change also the WebDav server admin credentials
  2545. location.reload();
  2546. }
  2547. });
  2548. }
  2549.  
  2550. function updateWebDavAdmin(user, pass) {
  2551. var request = loadXMLDoc("/update_admin_account?user="+user+"&pass="+pass,"");
  2552. if (request.status < 200 && request.status > 300)
  2553. showDialog(getString("dialog_admin_acc_could_not_update"));
  2554. else {
  2555. admin_user_name = user;
  2556. admin_password = pass;
  2557. }
  2558. }
  2559.  
  2560. var restartTest;
  2561. function restartServer(){
  2562. makeGetRequest("/rpc/restart", {}, function(){
  2563. showDialogOverlay(function(){
  2564. return "<div class='spinner floatL'></div><div style='padding: 5px 0px 0px 10px;' class='floatL'>" + getString("serverrestarting") + "</div>"
  2565. }, {}, {});
  2566. restartTest = setInterval(function(){
  2567. makeGetRequest("/rpc/get_all", {}, function(){
  2568. clearInterval(restartTest);
  2569. hideDialogOverlay();
  2570. // Update aggregation info after the restart is complete on the Aggregation page to display the list of servers more quickly.
  2571. if(window.location.hash == '#aggregation') {
  2572. // Callback must be on a short timeout in order to work since rpc call needs a short amount of time to popuplate list of
  2573. // aggregation servers after restarting, if call is done without timeout, response is still empty.
  2574. setTimeout("updateAggregation()", 1500);
  2575. }
  2576. })
  2577. }, 1000);
  2578. });
  2579. }
  2580.  
  2581. function rescanFolders(){
  2582. makeGetRequest("/rpc/rescan", {}, null);
  2583. }
  2584.  
  2585. //Display a dialog that prompts the user before completing a server reset.
  2586. function promptReset(){
  2587. showDialogOverlay(function(){
  2588. return getString("resetprompt");
  2589. }, null, {
  2590. 1: {
  2591. text: getString("ok"),
  2592. onclick: "hideDialogOverlay(); resetServer()"
  2593. },
  2594. 2: {
  2595. text: getString("cancel"),
  2596. onclick: "hideDialogOverlay()"
  2597. }
  2598. });
  2599. }
  2600.  
  2601. var resetTest;
  2602. function resetServer(){
  2603. makeGetRequest("/rpc/reset", {}, function(){
  2604. showDialogOverlay(function(){
  2605. return "<div class='spinner floatL'></div><div style='padding: 5px 0px 0px 10px;' class='floatL'>" + getString("serverrestarting") + "</div>"
  2606. }, {}, {});
  2607. var t = setTimeout("waitingForServer()", 3000);
  2608. });
  2609. }
  2610. function waitingForServer() {
  2611. resetTest = setInterval(function(){
  2612. makeGetRequest("/rpc/get_all", {}, function(response){
  2613. if (response != "") {
  2614. clearInterval(resetTest);
  2615. setReloadSide = true;
  2616. hideDialogOverlay();
  2617. }
  2618. })
  2619. }, 2000);
  2620. }
  2621.  
  2622. function clearCache(){
  2623. makeGetRequest("/rpc/clear_cache", {}, null);
  2624. }
  2625.  
  2626.  
  2627. var resetTest;
  2628. function resetClients(){
  2629. makeGetRequest("/rpc/resetclients", {}, function(){
  2630. showDialogOverlay(function(){
  2631. return "<div class='spinner floatL'></div><div style='padding: 5px 0px 0px 10px;' class='floatL'>" + getString("clientreset") + "</div>"
  2632. }, {}, {});
  2633. resetTest = setInterval(function(){
  2634. makeGetRequest("/rpc/get_all", {}, function(){
  2635. clearInterval(resetTest);
  2636. hideDialogOverlay();
  2637. loadSharing();
  2638. })
  2639. }, 1000);
  2640. });
  2641. }
  2642.  
  2643. function viewLog(){
  2644. window.open("/rpc/log_getfile", "_blank");
  2645. }
  2646.  
  2647. function clearLog(){
  2648. makeGetRequest("/rpc/log_clear", {}, null);
  2649. }
  2650.  
  2651. //Add the active class to a button when the mouse is pressed.
  2652. function onButtonMouseDown(button){
  2653. var button = $(button);
  2654. button.addClass("active");
  2655. }
  2656.  
  2657. //Remove the active class from a button when the mouse is released.
  2658. function onButtonMouseUp(button){
  2659. var button = $(button);
  2660. button.removeClass("active");
  2661. }
  2662.  
  2663. function cancelSettings(){
  2664. resetChanged();
  2665. $(window).trigger("hashchange");
  2666. }
  2667.  
  2668. function showActionButtons(){
  2669. $("#actionButtonContainer").show();
  2670. $("#spinnerContainer").hide();
  2671. }
  2672.  
  2673. function hideActionButtons(){
  2674. $("#actionButtonContainer").hide();
  2675. $("#spinnerContainer").show();
  2676. }
  2677.  
  2678. //Display a dialog overlay and opaque the background to prevent the user from interacting with the page until
  2679. //the dialog is closed.
  2680. //contentConstructor: The function to be called in order to populate the contents of the dialog.
  2681. //contentArgs: Arguments to be passed to the content constructor.
  2682. //buttons: A collection of buttons to include in the dialog. Buttons should be in the format {"text": text, "onclick":
  2683. //"onClickFunction()"}, where text is the text to be shown on the button and onclick is the function to be called
  2684. //when the button is clicked, expressed as a string ("onClickFunction()" rather than onClickFunction).
  2685. function showDialogOverlay(contentConstructor, contentArgs, buttons, widthClass){
  2686. var dialog = $("#dialogOverlay");
  2687. if (dialog) {
  2688. dialog.remove();
  2689. }
  2690. var body = $(document.body);
  2691. var contentHtml = contentConstructor(contentArgs);
  2692. var buttonHtml = makeButtons(buttons);
  2693. var overlay = $("#overlay");
  2694. if (overlay.length < 1) {
  2695. body.append("<div id='overlay' class='overlay'></div>");
  2696. }
  2697. body.append('<div id="dialogOverlay" class="dialogWrapper ' + widthClass + '"> \
  2698. <b class="dialogTop"><b class="d1"></b><b class="d2"></b><b class="d3"></b><b class="d4"></b></b> \
  2699. <div class="dialogContentWrapper">\
  2700. <div class="dialogContent">\
  2701. ' +
  2702. contentHtml +
  2703. '\
  2704. <div class="dialogButtonContainer" id ="dialogButtonContainer">\
  2705. ' +
  2706. buttonHtml +
  2707. '\
  2708. </div>\
  2709. <div class="clear"></div>\
  2710. </div>\
  2711. </div>\
  2712. <b class="dialogBottom"><b class="d4"></b><b class="d3"></b><b class="d2"></b><b class="d1"></b></b></div>');
  2713. var dialog = $("#dialogOverlay");
  2714. var dialogWidth = dialog.outerWidth();
  2715. var left = (body.width() / 2) - (dialogWidth / 2);
  2716. dialog.css("left", left);
  2717. if (contentArgs && contentArgs.onstart) {
  2718. contentArgs.onstart();
  2719. }
  2720. }
  2721.  
  2722. //Iterate through the collection of buttons to produce the HTML for them.
  2723. //buttons: The collection of button objects.
  2724. function makeButtons(buttons){
  2725. var buttonHtml = "";
  2726. $.each(buttons, function(key, button){
  2727. buttonHtml += '\
  2728. <a class="actionbtnmd floatL" onclick="' + button.onclick + '" onmousedown="onButtonMouseDown(this)" onmouseup="onButtonMouseUp(this)">\
  2729. <span class="actionbtn_l"></span>\
  2730. <span class="actionbtn_c">' +
  2731. button.text +
  2732. '</span>\
  2733. <span class="actionbtn_r"></span>\
  2734. </a>';
  2735. });
  2736. return buttonHtml;
  2737. }
  2738.  
  2739. //Remove the dialog and opaque overlay.
  2740. function hideDialogOverlay(){
  2741. var overlay = $("#overlay");
  2742. overlay.remove();
  2743. var dialog = $("#dialogOverlay");
  2744. dialog.remove();
  2745. if (setReloadSide) reloadSide();
  2746. setReloadSide = false;
  2747. }
  2748.  
  2749. //A function to wrap retrieved JSON data in parentheses for eval-ing to prevent errors.
  2750. function parseJson(jsonData){
  2751. return eval("(" + jsonData + ")");
  2752. }
  2753.  
  2754. var mediaBrowsePageCount;
  2755. //The number of items to display on a page of content.
  2756. var smallMediaBrowsePageCount = 25;
  2757. var largeMediaBrowsePageCount = 35;
  2758.  
  2759. //Clear the center display area and update the left navigation for media browsing.
  2760. //id: The id of the media category (music, video, photo) to display.
  2761. //callback: An optional callback to be called after the media browse view has been initialized.
  2762. function loadMediaBrowse(id, callback){
  2763. //If the left navigation hasn't been populated, fetch the left nav HTML.
  2764. if ($("#leftColumn").length == 0) {
  2765. makeGetRequest("/webconfig/browse-nav.htm", {}, function(response){
  2766. var responseHtml = $(response);
  2767. replaceStrings(responseHtml);
  2768. $("#leftNavContainer").html(responseHtml);
  2769. $(".serverSettingsContentWrapper").html('<div class="breadcrumb"></div><div id="browseContents"></div></div><div class="clear"></div><div id="browsePagination"><div class="browsePages largeFont"></div></div>');
  2770. $(".serverSettingsContentWrapper").addClass("contentDisplay");
  2771. //Call this function again after the essential HTML elements have been created for UI pouplation.
  2772. loadMediaBrowse(id, callback);
  2773. });
  2774. }
  2775. //Otherwise, populate the left nav with the options returned from the server.
  2776. else {
  2777. showLoadingGraphic();
  2778. makeGetRequest("/json/feed/" + id, {}, function(response){
  2779. var html = "";
  2780. //Use the larger page count only for the id 0$2, which corresponds to Photos.
  2781. mediaBrowsePageCount = (id == "0$2") ? (largeMediaBrowsePageCount) : (smallMediaBrowsePageCount);
  2782. var json = parseJson(response);
  2783. $.each(json.containerContents, function(i, data){
  2784. if (data.objId == 0) {
  2785. var title = data.title;
  2786. // replace the myTwonky text with a link to the my.twonky.com web page
  2787. if (title.indexOf("myTwonky") >= 0) {
  2788. if (browser == "other") {
  2789. title = title.replace("myTwonky", "<a class=\'inlineLink\' href=\"javascript:openPortalLink(\'login24\')\">myTwonky</a>");
  2790. } else {
  2791. // Safari
  2792. title = title.replace("myTwonky", "<a class=\'inlineLink\' href=\" " + statusData["portallogin24"] + "\" target=\"_self\" onClick=\"javascript:startPortalCheckTimerOnClick(\'login24\')\">myTwonky</a>");
  2793. }
  2794. }
  2795. html += '<li id="' + data.objId + '" >' + title + '</li>';
  2796. } else
  2797. if (data.title == "myTwonky") {
  2798. // do not show myTwonky in the left navigation tree if disablemytwonky is set
  2799. if (!myTwonkyDisabled)
  2800. html += '<li id="' + data.objId + '" onclick="navigateTo(\'id=' + data.objId + '&startPage=0&count=' + data.childCount + '\')"><a>' + data.title + '</a></li>';
  2801. } else {
  2802. html += '<li id="' + data.objId + '" onclick="navigateTo(\'id=' + data.objId + '&startPage=0&count=' + data.childCount + '\')"><a>' + data.title + '</a></li>';
  2803. }
  2804. });
  2805. $("#browseNav").html(html);
  2806. if (callback) {
  2807. callback();
  2808. }
  2809. else {
  2810. $("#browseContents").html("");
  2811. $(".browsePages").html("");
  2812. $(".breadcrumb").html("");
  2813. }
  2814. //If the fragment has an id property in it, extract the id including and immediately after the slash.
  2815. //Use this to make sure the correct left nav option is highlighted.
  2816. var fragmentPieces = $.param.fragment().split("&");
  2817. if (fragmentPieces.length > 1) {
  2818. var fragmentId = fragmentPieces[0].split("=")[1];
  2819. var activeId = fragmentId.split("$").slice(0, 4);
  2820. var activeIdStr = activeId.join("$");
  2821. $("#" + activeIdStr.replace(/\$/g, "\\$").replace(/\//g, "\\/")).addClass("current");
  2822. }
  2823. });
  2824. //Apply the active class to the relevant top nav item.
  2825. $("a", "#nav").removeClass("active");
  2826. var clickedElement = $("#" + id.replace(/\$/g, "\\$"));
  2827. clickedElement.addClass("active");
  2828. hideLoadingGraphic();
  2829. }
  2830. }
  2831.  
  2832. //Update the center display area with the selected folder or list of media, along with breadcrumbs and pagination.
  2833. //id: The id to have its contents displayed.
  2834. //startItem: The index of the first item to display. Used for pagination.
  2835. //numItems: The number of child items. Used for building breadcrumb navigation.
  2836. function loadMediaContents(id, startItem, numItems, reloadContent){
  2837. showLoadingGraphic();
  2838. var cleanedId = id.replace(/\$/g, "\\$").replace(/\//g, "\\/");
  2839. var nullNodes = 0;
  2840. var nodes = 0;
  2841. //Left nav elements have the same id as their corresponding nodes in the media browse API, so if the id can be
  2842. //matched, highlight that element to indicate that it's the currently selected navigation item.
  2843. var clickedElement = $("#" + cleanedId);
  2844. var clickedElementText = $("a", clickedElement).text();
  2845. if ($("#" + cleanedId, "#browseNav").length > 0) {
  2846. $("li", "#browseNav").removeClass("current");
  2847. $("#" + cleanedId, "#browseNav").addClass("current");
  2848. }
  2849. var html = "";
  2850. var branchHtml = "";
  2851. var leafHtml = "";
  2852. var pageCount = (mediaBrowsePageCount > numItems) ? (numItems) : (mediaBrowsePageCount);
  2853. makeGetRequest("/json/feed/" + id, {
  2854. "start": startItem,
  2855. "count": pageCount
  2856. }, function(response){
  2857. var json = parseJson(response);
  2858. html += '<div class="subHeader"><span class="subheaderTitle">' + json.containerTitle + '</span></div>';
  2859. var photosContainer;
  2860. $.each(json.containerContents, function(i, data){
  2861. if (data.nodeType == "branch") {
  2862. // nodeType is branch - show thumbnail for container if possible
  2863. var thumbnail = "";
  2864. var objType = "";
  2865. if (id.substring(0,3) == "0$1") objType = "M";
  2866. if (id.substring(0,3) == "0$2") objType = "P";
  2867. if (id.substring(0,3) == "0$3") objType = "V";
  2868. // online folders and subfolders have no item count!
  2869. // if the event was triggered by the navigation menue (left side) -> was "myTwonky" selected by the user?
  2870. // otherwise check the breadcrumb (linked header) -> starts with "myTwonky" (e.g. myTwonky / My Channels)?
  2871. var onlineFolder = false;
  2872. var clickedBrowseNavElement = false;
  2873. if (clickedElementText == "myTwonky") {
  2874. onlineFolder = true;
  2875. clickedBrowseNavElement = true;
  2876. } else {
  2877. $("#browseNav li").each(function() {
  2878. if ($(this).text() == clickedElementText) clickedBrowseNavElement = true;
  2879. });
  2880. }
  2881. if (!clickedBrowseNavElement) {
  2882. if ($(".breadcrumb").length > 0) {
  2883. if ($(".breadcrumbItem:first")[0].innerHTML.substring(0, 8) == "myTwonky") onlineFolder = true;
  2884. }
  2885. }
  2886. if (data.thumbnail && objType != "P") {
  2887. // container with thumbnail
  2888. var thumbnailData = getThumbnailLink(data.thumbnail, objType, true);
  2889. thumbnail = '<img class="folderThumbnail" src="' + thumbnailData.link + thumbnailData.scale + '" onerror="loadDefaultThumbnail($(this), \'' + objType + '\')" />';
  2890. // show no item count for myTwonky folders
  2891. if (onlineFolder)
  2892. branchHtml += '<div class="byFolderContainer" onclick="onMediaNodeClicked(this, ' + data.childCount + ')" id="' + data.objId + '"><div id="title"><a class="truncate">' + data.title + '</a><div class="smallFont">&nbsp;</div></div><div class="folderImageWrapper">'+thumbnail+'</div></div>';
  2893. else
  2894. branchHtml += '<div class="byFolderContainer" onclick="onMediaNodeClicked(this, ' + data.childCount + ')" id="' + data.objId + '"><div id="title"><a class="truncate">' + data.title + '</a><div class="smallFont">' + data.childCount + ' items</div></div><div class="folderImageWrapper">'+thumbnail+'</div></div>';
  2895. } else {
  2896. // container with no thumbnail
  2897. // show no item count for myTwonky folders
  2898. if (onlineFolder)
  2899. branchHtml += '<div class="byFolderContainer" onclick="onMediaNodeClicked(this, ' + data.childCount + ')" id="' + data.objId + '"><a class="truncate">' + data.title + '</a><div class="smallFont">&nbsp;</div><div class="folderImageWrapper"><img class="folderThumbnail" src="/webconfig/spacer.gif" onload="getFolderThumbnail($(this), \'' + data.objId + '\')" /></div></div>';
  2900. else
  2901. branchHtml += '<div class="byFolderContainer" onclick="onMediaNodeClicked(this, ' + data.childCount + ')" id="' + data.objId + '"><a class="truncate">' + data.title + '</a><div class="smallFont">' + data.childCount + ' items</div><div class="folderImageWrapper"><img class="folderThumbnail" src="/webconfig/spacer.gif" onload="getFolderThumbnail($(this), \'' + data.objId + '\')" /></div></div>';
  2902. }
  2903. nodes++;
  2904. if (data.childCount == 0) nullNodes++;
  2905. }
  2906. else {
  2907. // nodeType is leaf
  2908. var thumbnail = "";
  2909. if (data.thumbnail && data.objType != "P") {
  2910. var thumbnailData = getThumbnailLink(data.thumbnail, data.objType);
  2911. thumbnail = '<img src="' + thumbnailData.link + thumbnailData.scale + '" onerror="loadDefaultThumbnail($(this), \'' + data.objType + '\')" />';
  2912. }
  2913. switch (data.objType) {
  2914. case "V":
  2915. var duration = data.duration.split(".")[0];
  2916. if (duration.length == 0) duration = data.duration;
  2917. if (!(duration.indexOf(":") > 0)) {
  2918. if (duration.length == 0) duration = "00:00";
  2919. if (duration.length == 1) duration = "00:0"+duration;
  2920. if (duration.length == 2) duration = "00:"+duration;
  2921. }
  2922. if (duration.length > 5) {
  2923. if (duration.split(":")[0] == "00") {
  2924. duration = duration.substring(3, duration.length);
  2925. } else {
  2926. if (duration.split(":")[0] == "0") {
  2927. duration = duration.substring(2, duration.length);
  2928. }
  2929. }
  2930. }
  2931. var timeDisplay = (duration) ? ('<div class="timeDisplay">' + duration + '</div>') : ("")
  2932. var datamime = data.mime;
  2933. //datamime = datamime.replace(/&amp;/g, "&");
  2934. //datamime = datamime.replace(/&quot;/g, "\"");
  2935. leafHtml += '<div class="myLibraryRow">\
  2936. <div class="myLibraryMediaIcon floatL">' + thumbnail + timeDisplay + '</div>\
  2937. <div>\
  2938. <div class="mediaData"><a class="largeFont" href="' +
  2939. data.link +
  2940. '" target="_blank">' +
  2941. data.title +
  2942. '</a></div>\
  2943. <div class="mediaData">' +
  2944. getString("filesize") +
  2945. ' ' +
  2946. Math.round((parseInt(data.contentsize) / 1048576) * 100) / 100 +
  2947. ' MB</div>\
  2948. <div class="mediaData">' +
  2949. getString("format") +
  2950. ' ' +
  2951. datamime +
  2952. '</div>\
  2953. <div class="mediaData">' +
  2954. getString("year") +
  2955. ' ' +
  2956. data.year +
  2957. '</div>\
  2958. </div>\
  2959. <div class="clear"></div>\
  2960. </div>';
  2961. break;
  2962. case "P":
  2963. if (!photosContainer) {
  2964. photosContainer = $('<div><div class="allPhotosContainer"></div></div>');
  2965. }
  2966. var resolutionPieces = data.resolution.split("x");
  2967. var width = parseInt(resolutionPieces[0]);
  2968. var height = parseInt(resolutionPieces[1]);
  2969. var thumbnailData = getThumbnailLink(data.thumbnail, 'P', false, width, height);
  2970. // Thumbnails for media fusion feeds are not working because scaling of non local images is not possible
  2971. if ((thumbnailData.link.indexOf("httpproxy/embedded") > 0) || (thumbnailData.link.indexOf("httpproxy/direct") > 0))
  2972. $(".allPhotosContainer", photosContainer).append('<a href="' + data.link + '" target="_blank"><div class="allPhotosItem"><img src="' + thumbnailData.link + '" onerror="loadDefaultThumbnail($(this), \'P\')" style="' + thumbnailData.clip + '"/></div></a>');
  2973. else $(".allPhotosContainer", photosContainer).append('<a href="' + data.link + '" target="_blank"><div class="allPhotosItem"><img src="' + thumbnailData.link + thumbnailData.scale + '" onerror="loadDefaultThumbnail($(this), \'P\')" style="' + thumbnailData.clip + '"/></div></a>');
  2974. break;
  2975. case "M":
  2976. var duration = data.duration.split(".")[0];
  2977. if (duration.length == 0) duration = data.duration;
  2978. if (!(duration.indexOf(":") > 0)) {
  2979. if (duration.length == 0) duration = "00:00";
  2980. if (duration.length == 1) duration = "00:0"+duration;
  2981. if (duration.length == 2) duration = "00:"+duration;
  2982. }
  2983. if (duration.length > 5) {
  2984. if (duration.split(":")[0] == "00") {
  2985. duration = duration.substring(3, duration.length);
  2986. } else {
  2987. if (duration.split(":")[0] == "0") {
  2988. duration = duration.substring(2, duration.length);
  2989. }
  2990. }
  2991. }
  2992. if (duration) {
  2993. duration = "(" + duration + ")";
  2994. }
  2995. leafHtml += '<div class="myLibraryListRow">\
  2996. <div class="myLibraryListIcon floatL">' + thumbnail + '</div>\
  2997. <div>\
  2998. <div class="mediaData"><a class="largeFont" href="' +
  2999. data.link +
  3000. '" target="_blank">' +
  3001. data.title +
  3002. '</a> <span class="largeFont">' +
  3003. duration +
  3004. '</span></div>\
  3005. <div class="mediaData">' +
  3006. getString("artist") +
  3007. ' ' +
  3008. data.artist +
  3009. '</div>\
  3010. <div class="mediaData">' +
  3011. getString("album") +
  3012. ' ' +
  3013. data.album +
  3014. '</div>\
  3015. <div class="mediaData">' +
  3016. getString("genre") +
  3017. ' ' +
  3018. data.genre +
  3019. '</div>\
  3020. </div>\
  3021. <div class="clear"></div>\
  3022. </div>';
  3023. break;
  3024. }
  3025. }
  3026. });
  3027. //Photos require an additional container for layout purposes, so if it exists, add it to the HTML.
  3028. if (photosContainer) {
  3029. $(".allPhotosContainer", photosContainer).append('<div class="clear"></div>')
  3030. leafHtml += photosContainer.html();
  3031. }
  3032. if (branchHtml) {
  3033. branchHtml = '<div>' + branchHtml + '</div><div class="clear"></div>';
  3034. }
  3035. if (leafHtml) {
  3036. leafHtml = '<div>' + leafHtml + '</div>';
  3037. //If the media type isn't photos, add a div to provide separation between folder and media display.
  3038. //Photos already have a degree of separation because of the extra photos wrapper.
  3039. if (branchHtml && !photosContainer) {
  3040. leafHtml = '<div class="mixedContentSeparator"></div>' + leafHtml;
  3041. }
  3042. }
  3043. if (branchHtml || leafHtml) {
  3044. html += branchHtml + leafHtml;
  3045. if ($(".active", "#nav").attr("id") == "0$1") {
  3046. makeGetRequest("/json/feed/" + json.parentId, null, function(data){
  3047. data = parseJson(data);
  3048. $.each(data.containerContents, function(key, value){
  3049. if (value.objId == json.objId && value.playlist) {
  3050. $(".subHeader", "#browseContents").after('<a class="actionbtnlg floatL playlistButton" onmousedown="onButtonMouseDown(this)" onmouseup="onButtonMouseUp(this)" href="' + value.playlist + '" target="_blank"><span class="actionbtn_l actionbtn_ico"><img class="icolg icolg_play" src="/webconfig/spacer.gif" /></span><span class="actionbtn_l"></span><span class="actionbtn_c"> ' + getString("play") + ' </span><span class="actionbtn_r"></span></a><div class="clear"></div>');
  3051. return false;
  3052. }
  3053. });
  3054. });
  3055. }
  3056. }
  3057. else {
  3058. var emptyMessage = "";
  3059. switch ($(".active", "#nav").attr("id")) {
  3060. case "0$1":
  3061. emptyMessage = getString("nomusic");
  3062. break;
  3063. case "0$2":
  3064. emptyMessage = getString("nophotos");
  3065. break;
  3066. case "0$3":
  3067. emptyMessage = getString("novideos");
  3068. break;
  3069. }
  3070. html += emptyMessage;
  3071. }
  3072. $("#browseContents").html(html);
  3073.  
  3074. var numPages = Math.ceil(numItems / pageCount);
  3075. var currentPageNum = (startItem / mediaBrowsePageCount) + 1;
  3076. var pagesHtml = "<div>";
  3077. if (numPages > 1) {
  3078. var lowerDisplay;
  3079. var upperDisplay;
  3080. //If there are 9 or less pages, display all of them.
  3081. if (numPages <= 9) {
  3082. lowerDisplay = 1;
  3083. upperDisplay = numPages;
  3084. }
  3085. else {
  3086. //Otherwise, display the current page, plus three pages in each direction.
  3087. lowerDisplay = currentPageNum - 3;
  3088. upperDisplay = currentPageNum + 3;
  3089. var numTooLow = 0;
  3090. var numTooHigh = 0;
  3091. //Determine if lowerDisplay is 0 or lower, since we can't display that.
  3092. if (lowerDisplay < 1) {
  3093. for (var i = 0; i < Math.abs(1 - lowerDisplay); i++) {
  3094. if (upperDisplay + 1 <= numPages) {
  3095. numTooLow++;
  3096. }
  3097. else {
  3098. return;
  3099. }
  3100. }
  3101. }
  3102. //Determine if upperDisplay is greater than the number of pages, since we can't display that.
  3103. if (upperDisplay > numPages) {
  3104. for (var i = 0; i < (upperDisplay - numPages); i++) {
  3105. if (lowerDisplay - 1 >= 1) {
  3106. numTooHigh++;
  3107. }
  3108. else {
  3109. return;
  3110. }
  3111. }
  3112. }
  3113. //If either display threshold is too low or too high, increment the other so 7 pages are always shown.
  3114. if (numTooLow) {
  3115. lowerDisplay += numTooLow;
  3116. upperDisplay += numTooLow;
  3117. }
  3118. if (numTooHigh) {
  3119. lowerDisplay -= numTooHigh;
  3120. upperDisplay -= numTooHigh;
  3121. }
  3122. }
  3123. var previousPagesHtml = "";
  3124. //If page 1 and page 2 aren't already displayed, show them.
  3125. if (1 < lowerDisplay) {
  3126. previousPagesHtml += makePaginationLink(id, 0 * pageCount, numItems, 1)
  3127. }
  3128. if (2 < lowerDisplay) {
  3129. previousPagesHtml += makePaginationLink(id, 1 * pageCount, numItems, 2)
  3130. }
  3131. if (previousPagesHtml) {
  3132. previousPagesHtml += " ... ";
  3133. pagesHtml += previousPagesHtml;
  3134. }
  3135. //Show a link for each page in the range of lowerDisplay to upperDisplay.
  3136. for (var i = lowerDisplay - 1; i < upperDisplay; i++) {
  3137. if ((i * pageCount) == startItem) {
  3138. pagesHtml += '<span>' + (i + 1) + '</span> ';
  3139. }
  3140. else {
  3141. pagesHtml += makePaginationLink(id, i * pageCount, numItems, i + 1)
  3142. }
  3143. }
  3144. var subsequentPagesHtml = "";
  3145. //If the last two pages aren't already displayed, show them.
  3146. if (numPages - 1 > upperDisplay) {
  3147. subsequentPagesHtml += makePaginationLink(id, (numPages - 2) * pageCount, numItems, numPages - 1)
  3148. }
  3149. if (numPages > upperDisplay) {
  3150. subsequentPagesHtml += makePaginationLink(id, (numPages - 1) * pageCount, numItems, numPages)
  3151. }
  3152. if (subsequentPagesHtml) {
  3153. subsequentPagesHtml = " ... " + subsequentPagesHtml;
  3154. pagesHtml += subsequentPagesHtml;
  3155. }
  3156. }
  3157. pagesHtml += "</div>";
  3158.  
  3159. //Display some text to indicate the current range of items and the total number.
  3160. if (numPages > 1) {
  3161. var endItem = (parseInt(startItem) + pageCount)
  3162. pagesHtml += "<div>" + (parseInt(startItem) + 1) + " - " + ((endItem < numItems) ? endItem : numItems) + " " + getString("of") + " " + numItems + "</div>";
  3163. }
  3164. $(".browsePages").html(pagesHtml);
  3165. //To provide a better user experience, when a media browse link is clicked, scroll back to the top of the page.
  3166. window.scrollTo(0, 0);
  3167.  
  3168. var breadcrumb = $(".breadcrumb");
  3169. var lastBreadcrumb = $(".breadcrumb > .breadcrumbItem:last");
  3170. //If there's no breadcrumb yet, add one.
  3171. if (lastBreadcrumb.length == 0) {
  3172. //If an element can be found that matches with the selected element, add inactive text to the breadcrumb.
  3173. if ($("a", clickedElement).length > 0) {
  3174. breadcrumb.append('<span class="breadcrumbItem" pathid="' + id + '" numitems="' + numItems + '">' + $("a", clickedElement).text() + '</span>');
  3175. lastBreadcrumb = $(".breadcrumb > .breadcrumbItem:last");
  3176. }
  3177. //Otherwise, the user has refreshed the page and a fresh breadcrumb needs to be generated.
  3178. else {
  3179. var idPieces = id.split("$");
  3180. //Offset indicates the number of $ + 1 in the id string. 4 is used because that produces an id
  3181. //that matches with the left nav items (e.g. 0$3/0$3$30 for By Date).
  3182. var offset = 3;
  3183. var levels = [];
  3184. var levelsHtml = {};
  3185. //Beginning with a left nav id, successively reconstruct id strings out of the full id by
  3186. //appending additional levels (marked by the $).
  3187. for (var i = 0; i < idPieces.length - offset + 1; i++) {
  3188. var newId = idPieces.slice(0, offset + i);
  3189. var newIdStr = newId.join("$");
  3190. levels.push(newIdStr);
  3191. }
  3192. var numLevels = levels.length;
  3193. var levelsFetched = 0;
  3194. //For each of the reconstructed level strings, build breadcrumb html (a link except for the last item).
  3195. //Store the HTML by id.
  3196. $.each(levels, function(i, value){
  3197. makeGetRequest("/json/feed" + value, {}, function(data){
  3198. data = parseJson(data);
  3199. //For the first level, highlight the matching left-nav item.
  3200. if (i == 0) {
  3201. $("#" + value.replace(/\$/g, "\\$").replace(/\//g, "\\/")).addClass("current");
  3202. }
  3203. if (i != levels.length - 1) {
  3204. levelsHtml[value] = '<span class="breadcrumbWrapper" pathid="' + value + '"><a onclick="navigateTo(\'id=' + value + '&startPage=0&count=' + data.containerItemCount + '\')"><span class="breadcrumbItem" pathid="' + value + '" numitems="' + data.containerItemCount + '">' + data.containerTitle + '</span></a> / </span>';
  3205. }
  3206. else {
  3207. levelsHtml[value] = '<span class="breadcrumbItem" pathid="' + value + '" numitems="' + data.containerItemCount + '">' + data.containerTitle + '</span>';
  3208. }
  3209. levelsFetched++;
  3210. //Once breadcrumb data has been fetched for all levels, insert it into the container.
  3211. if (levelsFetched == numLevels) {
  3212. $.each(levels, function(j, level){
  3213. breadcrumb.append(levelsHtml[level]);
  3214. });
  3215. }
  3216. });
  3217. });
  3218. }
  3219. }
  3220. else {
  3221. //Count the number of $ to determine how many levels deep the navigation is.
  3222. // for myTwonky count the M too.
  3223. var lb = lastBreadcrumb.attr("pathid");
  3224. if (lb.length > 0) lb = lb.replace(/M/g, "$");
  3225. var numBreadcrumbLevels = (lb) ? (lb.split("$").length - 1) : (0);
  3226. var id2 = id;
  3227. id2 = id2.replace(/M/g, "$");
  3228. var numIdLevels = id2.split("$").length - 1;
  3229.  
  3230. //Compare the number of levels in the breadcrumb to the number of levels of the id. If the id has more levels,
  3231. //add it to the breadcrumb and add a hyperlink to the previous breadcrumb item.
  3232. if (lastBreadcrumb.length > 0 && numIdLevels > numBreadcrumbLevels && lastBreadcrumb.attr("pathid")) {
  3233. if (lastBreadcrumb.length > 0) {
  3234. lastBreadcrumb.wrap('<span class="breadcrumbWrapper" pathid="' + lastBreadcrumb.attr("pathid") + '"><a onclick="navigateTo(\'id=' + lastBreadcrumb.attr("pathid") + '&startPage=0&count=' + lastBreadcrumb.attr("numItems") + '\')"></a> / </span>');
  3235. }
  3236. breadcrumb.append('<span class="breadcrumbItem" pathid="' + id + '" numitems="' + numItems + '">' + clickedElementText + '</span>');
  3237. }
  3238. //Otherwise, find the breadcrumb item with the same level as the new item. Replace the old item with the new one
  3239. //at the same level and remove the rest of the breadcrumb after that.
  3240. else {
  3241. var collection = ($(".breadcrumbWrapper", ".breadcrumb").length > 0) ? ($(".breadcrumbWrapper", ".breadcrumb")) : ($(".breadcrumb > .breadcrumbItem:last"));
  3242. $.each(collection, function(i, element){
  3243. element = $(element);
  3244. var elementBreadcrumbLevels = 0;
  3245. if (element.attr("pathid")) {
  3246. var p = element.attr("pathid");
  3247. p = p.replace(/M/g, "$");
  3248. elementBreadcrumbLevels = p.split("$").length - 1;
  3249. }
  3250. if (elementBreadcrumbLevels == numIdLevels) {
  3251. var newText = (clickedElement.length > 0) ? ($("a", clickedElement).text()) : ($(".breadcrumbItem[pathid=" + cleanedId + "]", ".breadcrumb").text());
  3252. element.nextAll().remove();
  3253. element.attr("pathid", id);
  3254. element.replaceWith('<span class="breadcrumbItem" pathid="' + id + '" numitems="' + numItems + '">' + newText + '</span>');
  3255. hideLoadingGraphic();
  3256. return false;
  3257. }
  3258. });
  3259. }
  3260. }
  3261. // start a second http-request if all containers has 0 items
  3262. if ((nullNodes == nodes) && nodes > 0 && !reloadContent) {
  3263. var str = "reloadMediaContent(\'"+id+"\', \'"+startItem+"\', \'"+numItems+"\')";
  3264. var timerReload = setTimeout(str,500);
  3265. } else hideLoadingGraphic();
  3266. });
  3267. }
  3268. function reloadMediaContent(id, startItem, numItems) {
  3269. loadMediaContents(id, startItem, numItems, true);
  3270. }
  3271.  
  3272. function onMediaNodeClicked(node, count){
  3273. var id = node.id;
  3274. navigateTo("id=" + id + "&startPage=0&count=" + count);
  3275. }
  3276.  
  3277. //Get the HTML for a pagination link.
  3278. //id: The id of the media node to browse to.
  3279. //pageCount: The start item for the media browse call.
  3280. //numItems: The number of child items.
  3281. //text: The text of the link.
  3282. function makePaginationLink(id, pageCount, numItems, text){
  3283. return '<a onclick="navigateTo(\'id=' + id + '&startPage=' + pageCount + '&count=' + numItems + '\')">' + text + '</a> '
  3284. }
  3285.  
  3286. var videoDefaultImg = "/webconfig/gen_video_100.png";
  3287. var videoWidth = 100;
  3288. var videoHeight = 100;
  3289. var musicDefaultImg = "/webconfig/gen_music_40.png";
  3290. var musicWidth = 40;
  3291. var musicHeight = 40;
  3292. var photoDefaultImg = "/webconfig/gen_photo_100.png";
  3293. var photoWidth = 100;
  3294. var photoHeight = 100;
  3295. var videoFolderDefaultImg = "/webconfig/gen_folder_video.png";
  3296. var musicFolderDefaultImg = "/webconfig/gen_folder_music_110.png";
  3297. var photoFolderDefaultImg = "/webconfig/gen_folder_photo.png";
  3298. var folderWidth = 185;
  3299. var musicFolderWidth = 110;
  3300. var folderHeight = 110;
  3301.  
  3302. //Given a thumbnail tag, separate the link from it by parsing it out from between the quotes of the url attribute.
  3303. //thumbnailValue: The <media:thumbnail> tag to parse.
  3304. //mediaType: The type of media that a thumbnail is being retrieved for.
  3305. //isFolder: Default false. Indicates whether the thumbnail is for a folder display or for media display.
  3306. //originalWidth: Populated only for Photos. The original width of the image.
  3307. //originalHeight: Populated only for Photos. The original height of the image.
  3308. function getThumbnailLink(thumbnailValue, mediaType, isFolder, originalWidth, originalHeight){
  3309. var thumbnailObj = {
  3310. "link": "",
  3311. "scale": "",
  3312. "clip": ""
  3313. };
  3314. if (thumbnailValue) {
  3315. var firstQuote = thumbnailValue.indexOf('"');
  3316. var endChar = (thumbnailValue.lastIndexOf('?') > -1) ? (thumbnailValue.lastIndexOf('?')) : (thumbnailValue.length);
  3317. thumbnailObj.link = thumbnailValue.substring(firstQuote + 1, endChar);
  3318. if (isFolder) {
  3319. if (mediaType == "P") {
  3320. //thumbnailObj.link = photoFolderDefaultImg;
  3321. var scaleData = getImageScale(originalWidth, originalHeight, folderWidth, folderHeight);
  3322. thumbnailObj.scale = "?scale=" + scaleData.x + "x" + scaleData.y;
  3323. thumbnailObj.clip = scaleData.clip;
  3324. }
  3325. else
  3326. if (mediaType == "M") {
  3327. //thumbnailObj.link = musicFolderDefaultImg;
  3328. thumbnailObj.scale = "?scale=" + musicFolderWidth + "x" + folderHeight;
  3329. }
  3330. else {
  3331. //thumbnailObj.link = videoFolderDefaultImg;
  3332. thumbnailObj.scale = "?scale=" + folderWidth + "x" + folderHeight;
  3333. }
  3334. }
  3335. else {
  3336. switch (mediaType) {
  3337. case "V":
  3338. thumbnailObj.scale = "?scale=" + videoWidth + "x" + videoHeight;
  3339. break;
  3340. case "M":
  3341. thumbnailObj.scale = "?scale=" + musicWidth + "x" + musicHeight;
  3342. break;
  3343. case "P":
  3344. var scaleData = getImageScale(originalWidth, originalHeight, photoWidth, photoHeight);
  3345. thumbnailObj.scale = "?scale=" + scaleData.x + "x" + scaleData.y;
  3346. thumbnailObj.clip = scaleData.clip;
  3347. break;
  3348. }
  3349. }
  3350. return thumbnailObj;
  3351. }
  3352. }
  3353.  
  3354. //Recursively navigate into a node until the first leaf node is identified, then set the thumbnail of that node
  3355. //to an image.
  3356. //image: The image to be updated when the thumbnail is identified.
  3357. //id: The id to navigate into.
  3358. function getFolderThumbnail(image, id){
  3359. makeGetRequest("/json/feed/" + id, {
  3360. "start": 0,
  3361. "count": 1
  3362. }, function(response){
  3363. var json = parseJson(response);
  3364. if (json.containerContents.length == 0) {
  3365. return;
  3366. }
  3367. switch (json.containerContents[0].nodeType) {
  3368. case "branch":
  3369. getFolderThumbnail(image, json.containerContents[0].objId)
  3370. break;
  3371. case "leaf":
  3372. var width;
  3373. var height;
  3374. var thumbnailData;
  3375. if (json.containerContents[0].objType == "P") {
  3376. var resolutionPieces = json.containerContents[0].resolution.split("x");
  3377. width = parseInt(resolutionPieces[0]);
  3378. height = parseInt(resolutionPieces[1]);
  3379. thumbnailData = getThumbnailLink(json.containerContents[0].thumbnail, json.containerContents[0].objType, true, width, height);
  3380. }
  3381. else {
  3382. thumbnailData = getThumbnailLink(json.containerContents[0].thumbnail, json.containerContents[0].objType, true);
  3383. }
  3384. if (thumbnailData.link == videoDefaultImg || thumbnailData.link == musicDefaultImg || thumbnailData.link == photoDefaultImg) {
  3385. loadDefaultThumbnail(image, json.containerContents[0].objType);
  3386. }
  3387. else {
  3388. //thumbnail = '<img class="folderThumbnail" src="' + data.thumbnail + '" onerror="loadDefaultThumbnail($(this), \'' + objType + '\')" />';
  3389. //image.replaceWith('<img src="' + thumbnailData.link + thumbnailData.scale + '" onerror="loadDefaultThumbnail($(this), \'' + json.containerContents[0].objType + '\')" style="' + thumbnailData.clip + '"/>');
  3390. image.replaceWith('<img class="folderThumbnail" src="' + thumbnailData.link + thumbnailData.scale + '" onerror="loadDefaultThumbnail($(this), \'' + json.containerContents[0].objType + '\')" style="' + thumbnailData.clip + '"/>');
  3391. }
  3392. break;
  3393. }
  3394. });
  3395. }
  3396.  
  3397. //Load the default thumbnail for an image if the one specified in the media browse API can't be successfully loaded.
  3398. //image: The image to change the src of.
  3399. //mediaType: The media type of the node (video, music, photo). Used to determine which image to display.
  3400. function loadDefaultThumbnail(image, mediaType){
  3401. var imagePath;
  3402. //If the image is a child of an element with the byFolderContainer class, use the larger image.
  3403. //Otherwise, use the smaller image for that content type.
  3404. switch (mediaType) {
  3405. case "V":
  3406. imagePath = (image.parent().is(".byFolderContainer")) ? (videoFolderDefaultImg) : (videoDefaultImg);
  3407. break;
  3408. case "M":
  3409. imagePath = (image.parent().is(".byFolderContainer")) ? (musicFolderDefaultImg) : (musicDefaultImg);
  3410. break;
  3411. case "P":
  3412. imagePath = (image.parent().is(".byFolderContainer")) ? (photoFolderDefaultImg) : (photoDefaultImg);
  3413. break;
  3414. }
  3415. image.attr("src", imagePath);
  3416. }
  3417.  
  3418. //Given the original dimensions of an image, scale it to a new size and preserve the aspect ratio.
  3419. //originalWidth, originalHeight: The dimensions of the image to be scaled.
  3420. //desiredWidth, desiredHeight: The dimensions that the image should be scaled to.
  3421. function getImageScale(originalWidth, originalHeight, desiredWidth, desiredHeight){
  3422. var scaleObj = {
  3423. "x": "",
  3424. "y": "",
  3425. "clip": ""
  3426. };
  3427. //If the image is a landscape (the width is greater than the height), assign the largest dimension to the width.
  3428. if (originalWidth >= originalHeight) {
  3429. var ratio = originalHeight / originalWidth;
  3430. var scaledHeight = ratio * desiredWidth;
  3431. if (desiredHeight > scaledHeight) {
  3432. var newRatio = desiredHeight / scaledHeight;
  3433. scaleObj.x = Math.round(newRatio * desiredWidth);
  3434. scaleObj.y = Math.round(desiredHeight);
  3435. }
  3436. else {
  3437. scaleObj.x = Math.round(desiredWidth);
  3438. scaleObj.y = Math.round(ratio * desiredWidth);
  3439. }
  3440. }
  3441. //Do the reverse if the image is a portrait (height is greater than width).
  3442. else {
  3443. var ratio = originalWidth / originalHeight;
  3444. var scaledWidth = ratio * desiredHeight;
  3445. if (desiredWidth > scaledWidth) {
  3446. var newRatio = desiredWidth / scaledWidth;
  3447. scaleObj.x = Math.round(desiredWidth);
  3448. scaleObj.y = Math.round(newRatio * desiredHeight);
  3449. }
  3450. else {
  3451. scaleObj.x = Math.round(ratio * desiredHeight);
  3452. scaleObj.y = Math.round(desiredHeight);
  3453. }
  3454. }
  3455. var widthOffset = 0;
  3456. var heightOffset = 0;
  3457. if (scaleObj.x > desiredWidth) {
  3458. widthOffset = (parseInt(scaleObj.x) - desiredWidth) / 2;
  3459. }
  3460. if (scaleObj.y > desiredHeight) {
  3461. heightOffset = (parseInt(scaleObj.y) - desiredHeight) / 2;
  3462. }
  3463. scaleObj.clip = "clip: rect(" + heightOffset + "px " + (scaleObj.x - widthOffset) + "px " + (scaleObj.y - heightOffset) + "px " + widthOffset + "px); left: -" + widthOffset + "px; top: -" + heightOffset + "px;";
  3464. return scaleObj;
  3465. }
  3466.  
  3467. function toggleContainer(clickedButton)
  3468. {
  3469. var parent = clickedButton.parents(".boxHeader");
  3470. var toggleElement = $(parent).next();
  3471. var elementID = clickedButton.attr("id");
  3472. if (toggleElement.css("display") == "none") {
  3473. toggleElement.show();
  3474. $(".toggleText", clickedButton).text(getString("hide"));
  3475. clickedButton.removeClass("hidden");
  3476. clickedButton.addClass("showing");
  3477. document.cookie = elementID + "=show;";
  3478. }
  3479. else {
  3480. toggleElement.hide();
  3481. $(".toggleText", clickedButton).text(getString("show"));
  3482. clickedButton.removeClass("showing");
  3483. clickedButton.addClass("hidden");
  3484. document.cookie = elementID + "=hide;";
  3485. }
  3486. }
  3487.  
  3488.  
  3489. // ------------------------------------------
  3490. // synchronization (WebDav server)
  3491. // ------------------------------------------
  3492. var shares_alias_array = new Array();
  3493. var shares_path_array = new Array();
  3494. var shares_user_array = new Array();
  3495. var shares_rights_array = new Array();
  3496. var user_array = new Array();
  3497. var rights_user_array = new Array();
  3498. var rights_share_array = new Array();
  3499. var rights_mode_array = new Array();
  3500.  
  3501. var values_loaded=0;
  3502. var reserve_user_name = "Any";
  3503.  
  3504.  
  3505. function loadSynchronization(){
  3506. // getMetaInfo();
  3507. populateSettingsNav();
  3508. makeGetRequest("/webconfig/synchronization.htm", {}, function(response){
  3509. var responseHtml = $(response);
  3510. replaceStrings(responseHtml);
  3511. showToggleButtons(responseHtml);
  3512. $("#userslist",responseHtml).html(getUserList());
  3513. $("#sharedlist",responseHtml).html(getShareList());
  3514. $(".serverSettingsContentWrapper").html(responseHtml);
  3515. highlightNav($("#nav_synchronization"));
  3516. });
  3517. }
  3518.  
  3519. function getMetaInfo() {
  3520. if (!getServerDetails()) return;
  3521. var rawdata = getServerDetails().responseText;
  3522. var lines = rawdata.split("\n");
  3523. server_name = lines[0];
  3524. server_port = lines[1];
  3525. server_version = lines[2];
  3526. //globalLanguage = lines[3]
  3527. server_start_time = lines[4];
  3528. server_build_date = lines[5];
  3529. }
  3530. function getServerDetails() {
  3531. return loadXMLDoc("/get_server_info","");
  3532. }
  3533.  
  3534. function showDialog(msg, handler){
  3535. showDialogOverlay(function(){
  3536. return msg;
  3537. }, {}, {
  3538. 1: {
  3539. text: getString("ok"),
  3540. onclick: "hideDialogOverlay(); " + handler
  3541. }
  3542. });
  3543. }
  3544. function confirmDialog(msg,handler) {
  3545. showDialogOverlay(function(){
  3546. return msg;
  3547. }, null, {
  3548. 1: {
  3549. text: getString("ok"),
  3550. onclick: handler
  3551. },
  3552. 2: {
  3553. text: getString("cancel"),
  3554. onclick: "hideDialogOverlay()"
  3555. }
  3556. });
  3557. }
  3558.  
  3559. // status subheader: reload
  3560. function reloadConfig() {
  3561. var request = loadXMLDoc("/reload","");
  3562. if (request.status != 200) {
  3563. showDialog(getString("reload_failed"));
  3564. } else {
  3565. window.location.reload();
  3566. }
  3567. highlightNav($("#nav_synchronization"));
  3568. }
  3569.  
  3570. function getUserList() {
  3571. var i;
  3572. var strOut = "";
  3573. var numUsers = 0;
  3574. if (!values_loaded) loadAll();
  3575. numUsers = user_array.length
  3576.  
  3577. if (numUsers <= 0) {
  3578. strOut += "<font color=\"red\">" + getString("no_user_added") + "</font>";
  3579. } else {
  3580. strOut += "<select class=\"selectUserInput floatL\" id=\"user\">";
  3581. for (i=0;i<numUsers;i++) {
  3582. strOut += "<option "+((i==0)?"selected ":"")+"value=\""+user_array[i]+"\">"+user_array[i]+"</option>";
  3583. }
  3584. strOut += "</select>";
  3585. strOut += "<a class=\"actionbtn floatL\" onmousedown=\"onButtonMouseDown(this)\" onmouseup=\"onButtonMouseUp(this)\" onclick=\"deleteUser();\"> <span class=\"actionbtn_l\"></span><span class=\"actionbtn_c\">"+getString("delete")+"</span><span class=\"actionbtn_r\"></span></a>";
  3586. strOut += "<div class=\"smallServerContentSpacer\"></div>";
  3587. }
  3588. return strOut;
  3589. }
  3590. function loadAll() {
  3591. var rawdata=getShares().responseText;
  3592. if (rawdata == "failed") return;
  3593. var lines=rawdata.split("\n");
  3594. var len = parseInt(lines.length/4);
  3595. shares_alias_array = new Array(len);
  3596. shares_path_array = new Array(len);
  3597. shares_user_array = new Array(len);
  3598. shares_rights_array = new Array(len);
  3599. for (i=0;i<len;i++) {
  3600. shares_alias_array[i]=lines[4*i];
  3601. shares_path_array[i]=lines[4*i+1];
  3602. shares_user_array[i]=lines[4*i+2];
  3603. shares_rights_array[i]=lines[4*i+3];
  3604. }
  3605.  
  3606. rawdata = getUsers().responseText;
  3607. if (rawdata == "failed") return;
  3608. lines = rawdata.split("\n");
  3609. len = lines.length-1;
  3610. user_array = new Array(len);
  3611. for (i=0;i<len;i++) {
  3612. user_array[i]=lines[i];
  3613. }
  3614.  
  3615. rawdata=getRights().responseText;
  3616. if (rawdata == "failed") return;
  3617. lines=rawdata.split("\n");
  3618. len = parseInt(lines.length/3);
  3619. rights_user_array = new Array(len);
  3620. rights_share_array = new Array(len);
  3621. rights_mode_array = new Array(len);
  3622. for (i=0;i<len;i++) {
  3623. rights_user_array[i]=lines[3*i];
  3624. rights_share_array[i]=lines[3*i+1];
  3625. rights_mode_array[i]=lines[3*i+2];
  3626. }
  3627. values_loaded=1;
  3628. }
  3629. function getShares() {
  3630. var request = loadXMLDoc("/get_shares","");
  3631. if (request.status != 200) {
  3632. showDialog(getString("dialog_server_req_failed"));
  3633. request.responseText = "failed";
  3634. }
  3635. return request;
  3636. }
  3637. function getUsers() {
  3638. var request = loadXMLDoc("/get_users","");
  3639. if (request.status != 200) {
  3640. showDialog(getString("dialog_server_req_failed"));
  3641. request.responseText = "failed";
  3642. }
  3643. return request;
  3644. }
  3645. function getRights() {
  3646. var request = loadXMLDoc("/get_rights","");
  3647. if (request.status != 200) {
  3648. showDialog(getString("dialog_server_req_failed"));
  3649. request.responseText = "failed";
  3650. }
  3651. return request;
  3652. }
  3653.  
  3654.  
  3655. // delete and add users
  3656. function deleteUser() {
  3657. var user = $("#user").val();
  3658. var msg = formatString(getString("dialog_delete_user"),[user,user]);
  3659. confirmDialog(msg,"confirmDeleteUser()");
  3660. }
  3661. function confirmDeleteUser() {
  3662. var user = $("#user").val();
  3663. user = encodeURIComponent(user);
  3664. var request = loadXMLDoc("/delete_user?user="+user,"");
  3665. if (request.status != 200) {
  3666. showDialog(getString("dialog_server_req_failed"));
  3667. } else {
  3668. updateSharesForUser(user);
  3669. window.location.reload();
  3670. highlightNav($("#nav_synchronization"));
  3671. }
  3672. }
  3673. function updateSharesForUser(user) {
  3674. var len = shares_alias_array.length;
  3675. var i = 0;
  3676. for (i=0;i<len;i++) {
  3677. if (shares_user_array[i].length <= 0) continue;
  3678. if (shares_user_array[i] != user) continue;
  3679. removeRight(shares_alias_array[i]);
  3680. }
  3681. }
  3682. function removeRight(alias) {
  3683. alias = encodeURIComponent(alias);
  3684. var request = loadXMLDoc("/remove_right?alias="+alias,"");
  3685. if (request.status != 200) {
  3686. showDialog(getString("dialog_server_req_failed"));
  3687. return 0;
  3688. }
  3689. return 1;
  3690. }
  3691. function highlightText(field) {
  3692. if(field!=null) {
  3693. field.focus();
  3694. field.select();
  3695. }
  3696. }
  3697.  
  3698. function handleKeyPress(event) {
  3699. // escape key
  3700. if (event.keyCode==27) {
  3701. hideDialogOverlay();
  3702. }
  3703. }
  3704. function promptUserDialog(msg, handler, ispassword){
  3705. var inputtype="text";
  3706. var inputvalue=msg;
  3707. if(ispassword) {
  3708. inputtype = "password";
  3709. inputvalue = "";
  3710. }
  3711. showDialogOverlay(function(){
  3712. return "<div>" + msg + "</div>"
  3713. + "<input type=\""+inputtype+"\" id=\"promptInput\" align='center' type=\"text\" value=\"" + inputvalue + "\" onkeyup=\"handleKeyPress(event)\" onclick=\"highlightText(this)\"/>";
  3714. }, null, {
  3715. 1: {
  3716. text: getString("ok"),
  3717. onclick: handler
  3718. },
  3719. 2: {
  3720. text: getString("cancel"),
  3721. onclick: "hideDialogOverlay()"
  3722. }
  3723. });
  3724. }
  3725. function addUser() {
  3726. promptUserDialog(getString("enter_valid_un"),"userEntered()", false);
  3727. }
  3728. var validUser;
  3729. function userEntered(){
  3730. var user = $("#promptInput").val();
  3731. if (user == getString("enter_valid_un")) {
  3732. user = '';
  3733. } else if (user.toLowerCase().replace(/\s/g, "") == reserve_user_name.toLowerCase()) {
  3734. showDialog(formatString(getString("dialog_reserve_user_name"),[reserve_user_name]));
  3735. return;
  3736. }
  3737. if (user.length > 0) {
  3738. validUser = encodeURIComponent(user);
  3739. promptUserDialog(getString("enter_valid_pw"),"passwordEntered()", true);
  3740. } else {
  3741. showDialog(getString("dialog_enter_valid_un"));
  3742. }
  3743. }
  3744. function passwordEntered () {
  3745. var pw = $("#promptInput").val();
  3746. if (pw == getString("enter_valid_pw")) {
  3747. pw = '';
  3748. }
  3749. if (pw.length > 0) {
  3750. pw = encodeURIComponent(pw);
  3751. var request = loadXMLDoc("/add_user?user=" + validUser + "&pass=" +pw,"");
  3752. if (request.status != 200) {
  3753. showDialog(getString("dialog_server_req_failed"));
  3754. } else {
  3755. showDialog(getString("dialog_user_add_success"),"window.location.reload()");
  3756. }
  3757. } else {
  3758. showDialog(getString("dialog_enter_valid_pw"));
  3759. }
  3760. }
  3761.  
  3762.  
  3763. // SHARES
  3764. function getShareList() {
  3765. folderBrowseDialogMsg = 2;
  3766. var i;
  3767. var strOut = "";
  3768. var newlink = "";
  3769. if (!values_loaded) loadAll();
  3770. var numSharesPresent = shares_alias_array.length;
  3771.  
  3772. if (numSharesPresent <= 0) {
  3773. strOut += "<font color=\"red\">" + getString("no_syncfolders") + "</font>";
  3774. }
  3775. else {
  3776. // table columns: share name, share path, user, share rights, button delete share, button view share
  3777. strOut += "<table class='syncTable'><tr>"
  3778. + "<th>" + getString("syncfolder_name") + "</th>"
  3779. + "<th>" + getString("local_folder") + "</th>"
  3780. + "<th style=\"text-align:center\">" + getString("username") + "</th>"
  3781. + "<th style=\"text-align:center\">" + getString("rights") + "</th>"
  3782. + "<th></th>"
  3783. + "<th></th>"
  3784. + "</tr>";
  3785. var uname = reserve_user_name;
  3786. // Get the existing shares
  3787. for (i=0;i<shares_alias_array.length;i++) {
  3788. if (shares_user_array[i].length > 0)
  3789. uname = shares_user_array[i];
  3790. else
  3791. uname = reserve_user_name;
  3792. strOut += "<tr><td><input class=\"floatL\" type=\"text\" readonly=\"readonly\" disabled=\"true\" value=\"" + shares_alias_array[i] + "\"/>"
  3793. + "</td><td>"
  3794. + "<input class=\"longInput floatL\" type=\"text\" readonly=\"readonly\" disabled=\"true\" value=\"" + shares_path_array[i] + "\"/>"
  3795. + "</td><td>"
  3796. + "<input class=\"webdavuser floatL\" style=\"text-align:center\" type=\"text\" readonly=\"readonly\" disabled=\"true\" value=\"" + uname + "\"/>"
  3797. + "</td><td>"
  3798. + "<input class=\"webdavrights floatL\" style=\"text-align:center\" type=\"text\" readonly=\"readonly\" disabled=\"true\" value=\"" + shares_rights_array[i] + "\"/>"
  3799. + "</td><td>"
  3800. + "<a style=\"width:100%\" class=\"actionbtn floatL\" onmousedown=\"onButtonMouseDown(this)\" onmouseup=\"onButtonMouseUp(this)\" onClick=\"deleteShare('"+ shares_alias_array[i] +"');\">"
  3801. + "<span class=\"actionbtn_l\"></span><span class=\"actionbtn_c\">" + getString('delete') + "</span><span class=\"actionbtn_r\"></span>"
  3802. + "</a></td>"
  3803. + "<td>"
  3804. + "<a style=\"width:100%\" class=\"actionbtn floatL\" onmousedown=\"onButtonMouseDown(this)\" onmouseup=\"onButtonMouseUp(this)\" onClick=\"openShare(" + i + ");\">"
  3805. + "<span class=\"actionbtn_l\"></span><span class=\"actionbtn_c\">" + getString('view') + "</span><span class=\"actionbtn_r\"></span>"
  3806. + "</a></td>"
  3807. + "</tr>";
  3808. }
  3809. strOut += "</table>";
  3810. }
  3811. strOut += "<div class=\"smallServerContentSpacer\"/>"
  3812. strOut += "<div><b><span class=\"title\">" + getString("syncfolder_new_share_info") + "</span></div></b>";
  3813. // table columns: share name, sahre path, button browse path, user, share rights
  3814. strOut += "<table class='syncTable'><tr>"
  3815. + "<th>" + getString("syncfolder_name") + "</th>"
  3816. + "<th>" + getString("local_folder") + "</th>"
  3817. + "<th></th>"
  3818. + "<th>" + getString("username") + "</th>"
  3819. + "<th>" + getString("rights") + "</th>"
  3820. + "</tr>";
  3821. strOut += "<tr><td>"
  3822. + "<input id=\"shareAlias\" class=\"pathInput floatL\" type=\"text\" value=\"\" />"
  3823. + "</td><td>"
  3824. + "<input id=\"pathInput1\" readonly=\"readonly\" class=\"longInput floatL\" type=\"text\" value=\"\"/>"
  3825. + "</td><td>"
  3826. + "<a style=\"width:100%\" class=\"actionbtn floatL\" onmousedown=\"onButtonMouseDown(this)\" onmouseup=\"onButtonMouseUp(this)\" onClick=\"showFolderBrowse('1');\">"
  3827. + "<span class=\"actionbtn_l\"></span><span class=\"actionbtn_c\">" + getString("browse") + "</span><span class=\"actionbtn_r\"></span>"
  3828. + "</a></td><td>"
  3829. + "<select class=\"selectUserInput floatL\" id=\"userInput\" onchange=\"updateRight(this.value)\">";
  3830. for (i = 0; i < user_array.length; i++) {
  3831. if (i == 0) strOut += "<option selected=\"selected\" value=\"" + user_array[i] + "\">" + user_array[i] + "</option>";
  3832. else strOut += "<option value=\"" + user_array[i] + "\">" + user_array[i] + "</option>";
  3833. }
  3834. strOut += "<option value=\"" + reserve_user_name + "\">" + getString("any") + "</option></select>"
  3835. + "</td><td>";
  3836. if (user_array.length == 0)
  3837. strOut += "<select class=\"selectRightsInput floatL\" id=\"right\">"
  3838. + "<option selected=\"selected\" value=\"r/w\">r/w</option>"
  3839. + "</select></td></tr>";
  3840. else
  3841. strOut += "<select class=\"selectRightsInput floatL\" id=\"right\">"
  3842. + "<option selected=\"selected\" value=\"r/w\">r/w</option>"
  3843. + "<option value=\"r/o\">r/o</option>"
  3844. + "</select></td></tr>";
  3845. strOut += "</table>";
  3846. strOut += "<div class=\"verySmallServerContentSpacer\"></div>";
  3847. return strOut;
  3848. }
  3849. function updateRight(val) {
  3850. var elem = document.getElementById("right");
  3851. elem.options.length = 0;
  3852. if (val == reserve_user_name) {
  3853. elem.options[0] = new Option("r/w", "r/w",true);
  3854. } else {
  3855. elem.options[0] = new Option("r/w", "r/w",true);
  3856. elem.options[1] = new Option("r/o", "r/o");
  3857. }
  3858. }
  3859. function getShareUrl(idx)
  3860. {
  3861. var url = shares_alias_array[idx];
  3862. var lines = url.split("/");
  3863. if (lines.length > 1) {
  3864. url = "/" + encodeURIComponent(lines[1]);
  3865. }
  3866. if (shares_alias_array[idx] != "/") {
  3867. url += "/";
  3868. }
  3869. return statusData["syncurl"] + url;
  3870. }
  3871. function openShare(idx) {
  3872. window.open(getShareUrl(idx));
  3873. }
  3874.  
  3875. // add shares and rights, delete shares
  3876. function addShareAndRights() {
  3877. var alias = $("#shareAlias").val();
  3878. var folder = $("#pathInput1").val();
  3879. var user = $("#userInput").val();
  3880. var right = $("#right").val();
  3881. var result = 0;
  3882. var validRights = 0;
  3883. var enableAuth = 1;
  3884. if (user.toLowerCase().replace(/\s/g, "") == reserve_user_name.toLowerCase()) {
  3885. enableAuth = 0;
  3886. }
  3887.  
  3888. result = addShare(alias, folder)
  3889. if (1 == result) {
  3890. if (enableAuth == 1) {
  3891. result = addRight(alias, user, right);
  3892. } else {
  3893. result = removeRight(alias);
  3894. }
  3895. if (1 == result) {
  3896. showDialog(getString("dialog_share_added_success"),"window.location.reload()");
  3897. }
  3898. }
  3899. }
  3900. function addRight(alias,user,mode) {
  3901. if (alias.charAt(0) != '/')
  3902. alias = '/' + alias;
  3903. alias = encodeURIComponent(alias);
  3904. user = encodeURIComponent(user);
  3905. var request = loadXMLDoc("/rpc/webdav/add_right?alias="+alias+"&user="+user+"&mode="+mode,"");
  3906. if (request.status != 200) {
  3907. showDialog(getString("dialog_server_req_failed"));
  3908. return 0;
  3909. }
  3910. return 1;
  3911. }
  3912. function addShare(alias,path) {
  3913. if (alias==null || alias=="") {
  3914. showDialog(getString("dialog_enter_alias_name"));
  3915. return 0;
  3916. }
  3917.  
  3918. var lines = alias.split("\\");
  3919. if (lines.length > 1) {
  3920. showDialog(formatString(getString("dialog_invalid_share_name_2"),["\\"]));
  3921. return 0;
  3922. }
  3923.  
  3924. var lines = alias.split("/");
  3925. if (lines.length > 2) {
  3926. showDialog(formatString(getString("dialog_invalid_share_name_1"),["/","/","/","/","/"]));
  3927. return 0;
  3928. }
  3929.  
  3930. if (path==null || path=="") {
  3931. showDialog(getString("dialog_enter_share_dir"));
  3932. return 0;
  3933. }
  3934.  
  3935. if (alias.charAt(0) != '/')
  3936. alias = '/' + alias;
  3937.  
  3938. alias = encodeURIComponent(alias);
  3939. path = encodeURIComponent(path);
  3940.  
  3941. var request = loadXMLDoc("/add_share?alias="+alias+"&path="+path,"");
  3942. if (request.status != 200) {
  3943. showDialog(getString("dialog_invalid_share_path"));
  3944. return 0;
  3945. }
  3946. return 1;
  3947. }
  3948. function deleteShare(share) {
  3949. shareToDelete = encodeURIComponent(share);
  3950. var request = loadXMLDoc("/delete_share?share="+shareToDelete+"&tmp=","");
  3951. if (request.status != 200) {
  3952. showDialog(getString("dialog_failed_delete_share"));
  3953. } else {
  3954. window.location.reload();
  3955. highlightNav($("#nav_synchronization"));
  3956. }
  3957. }
  3958.  
  3959.  
  3960. function formatString(string2Fmt, values){
  3961. if (string2Fmt == null || values == null || values.length == 0)
  3962. return;
  3963. var len = values.length;
  3964. for (i=0;i<=len;i++){
  3965. string2Fmt = string2Fmt.replace("{" + i + "}", values[i]);
  3966. }
  3967. return string2Fmt;
  3968. }
  3969.  
  3970. function getWebDavUrl() {
  3971. return "/rpc/webdavproxy?/rpc/webdav";
  3972. }
  3973.  
  3974. // Helper function that does the actual RPC invocation
  3975. function loadXMLDoc(my_url,strData)
  3976. {
  3977. var req;
  3978. req = false;
  3979. // branch for native XMLHttpRequest object
  3980. if(window.XMLHttpRequest) {
  3981. try {
  3982. req = new XMLHttpRequest();
  3983. } catch(e) {
  3984. req = false;
  3985. }
  3986. // branch for IE/Windows ActiveX version
  3987. } else if(window.ActiveXObject) {
  3988. try {
  3989. req = new ActiveXObject("Msxml2.XMLHTTP");
  3990. } catch(e) {
  3991. try {
  3992. req = new ActiveXObject("Microsoft.XMLHTTP");
  3993. } catch(e) {
  3994. req = false;
  3995. }
  3996. }
  3997. }
  3998. if(req) {
  3999. my_url = getWebDavUrl() + my_url;
  4000. if (strData.length>0) { // post request
  4001. req.open("POST", my_url, false);
  4002. //req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
  4003. req.setRequestHeader('Content-Type', 'text/xml; charset=UTF-8');
  4004. req.send(strData);
  4005. }
  4006. else { // get request
  4007. req.open("GET", my_url, false);
  4008. try {
  4009. req.send("");
  4010. } catch(e) {
  4011. req = false;
  4012. }
  4013. }
  4014. return req;
  4015. }
  4016. return "";
  4017. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement