all.js 74 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067
  1. /* ---- lib/Class.coffee ---- */
  2. (function() {
  3. var Class,
  4. slice = [].slice;
  5. Class = (function() {
  6. function Class() {}
  7. Class.prototype.trace = true;
  8. Class.prototype.log = function() {
  9. var args;
  10. args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
  11. if (!this.trace) {
  12. return;
  13. }
  14. if (typeof console === 'undefined') {
  15. return;
  16. }
  17. args.unshift("[" + this.constructor.name + "]");
  18. console.log.apply(console, args);
  19. return this;
  20. };
  21. Class.prototype.logStart = function() {
  22. var args, name;
  23. name = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
  24. if (!this.trace) {
  25. return;
  26. }
  27. this.logtimers || (this.logtimers = {});
  28. this.logtimers[name] = +(new Date);
  29. if (args.length > 0) {
  30. this.log.apply(this, ["" + name].concat(slice.call(args), ["(started)"]));
  31. }
  32. return this;
  33. };
  34. Class.prototype.logEnd = function() {
  35. var args, ms, name;
  36. name = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : [];
  37. ms = +(new Date) - this.logtimers[name];
  38. this.log.apply(this, ["" + name].concat(slice.call(args), ["(Done in " + ms + "ms)"]));
  39. return this;
  40. };
  41. return Class;
  42. })();
  43. window.Class = Class;
  44. }).call(this);
  45. /* ---- lib/Promise.coffee ---- */
  46. (function() {
  47. var Promise,
  48. slice = [].slice;
  49. Promise = (function() {
  50. Promise.when = function() {
  51. var args, fn, i, len, num_uncompleted, promise, task, task_id, tasks;
  52. tasks = 1 <= arguments.length ? slice.call(arguments, 0) : [];
  53. num_uncompleted = tasks.length;
  54. args = new Array(num_uncompleted);
  55. promise = new Promise();
  56. fn = function(task_id) {
  57. return task.then(function() {
  58. args[task_id] = Array.prototype.slice.call(arguments);
  59. num_uncompleted--;
  60. if (num_uncompleted === 0) {
  61. return promise.complete.apply(promise, args);
  62. }
  63. });
  64. };
  65. for (task_id = i = 0, len = tasks.length; i < len; task_id = ++i) {
  66. task = tasks[task_id];
  67. fn(task_id);
  68. }
  69. return promise;
  70. };
  71. function Promise() {
  72. this.resolved = false;
  73. this.end_promise = null;
  74. this.result = null;
  75. this.callbacks = [];
  76. }
  77. Promise.prototype.resolve = function() {
  78. var back, callback, i, len, ref;
  79. if (this.resolved) {
  80. return false;
  81. }
  82. this.resolved = true;
  83. this.data = arguments;
  84. if (!arguments.length) {
  85. this.data = [true];
  86. }
  87. this.result = this.data[0];
  88. ref = this.callbacks;
  89. for (i = 0, len = ref.length; i < len; i++) {
  90. callback = ref[i];
  91. back = callback.apply(callback, this.data);
  92. }
  93. if (this.end_promise) {
  94. return this.end_promise.resolve(back);
  95. }
  96. };
  97. Promise.prototype.fail = function() {
  98. return this.resolve(false);
  99. };
  100. Promise.prototype.then = function(callback) {
  101. if (this.resolved === true) {
  102. callback.apply(callback, this.data);
  103. return;
  104. }
  105. this.callbacks.push(callback);
  106. return this.end_promise = new Promise();
  107. };
  108. return Promise;
  109. })();
  110. window.Promise = Promise;
  111. /*
  112. s = Date.now()
  113. log = (text) ->
  114. console.log Date.now()-s, Array.prototype.slice.call(arguments).join(", ")
  115. log "Started"
  116. cmd = (query) ->
  117. p = new Promise()
  118. setTimeout ( ->
  119. p.resolve query+" Result"
  120. ), 100
  121. return p
  122. back = cmd("SELECT * FROM message").then (res) ->
  123. log res
  124. return "Return from query"
  125. .then (res) ->
  126. log "Back then", res
  127. log "Query started", back
  128. */
  129. }).call(this);
  130. /* ---- lib/Prototypes.coffee ---- */
  131. (function() {
  132. String.prototype.startsWith = function(s) {
  133. return this.slice(0, s.length) === s;
  134. };
  135. String.prototype.endsWith = function(s) {
  136. return s === '' || this.slice(-s.length) === s;
  137. };
  138. String.prototype.repeat = function(count) {
  139. return new Array(count + 1).join(this);
  140. };
  141. window.isEmpty = function(obj) {
  142. var key;
  143. for (key in obj) {
  144. return false;
  145. }
  146. return true;
  147. };
  148. }).call(this);
  149. /* ---- lib/maquette.js ---- */
  150. (function (root, factory) {
  151. if (typeof define === 'function' && define.amd) {
  152. // AMD. Register as an anonymous module.
  153. define(['exports'], factory);
  154. } else if (typeof exports === 'object' && typeof exports.nodeName !== 'string') {
  155. // CommonJS
  156. factory(exports);
  157. } else {
  158. // Browser globals
  159. factory(root.maquette = {});
  160. }
  161. }(this, function (exports) {
  162. 'use strict';
  163. ;
  164. ;
  165. ;
  166. ;
  167. var NAMESPACE_W3 = 'http://www.w3.org/';
  168. var NAMESPACE_SVG = NAMESPACE_W3 + '2000/svg';
  169. var NAMESPACE_XLINK = NAMESPACE_W3 + '1999/xlink';
  170. // Utilities
  171. var emptyArray = [];
  172. var extend = function (base, overrides) {
  173. var result = {};
  174. Object.keys(base).forEach(function (key) {
  175. result[key] = base[key];
  176. });
  177. if (overrides) {
  178. Object.keys(overrides).forEach(function (key) {
  179. result[key] = overrides[key];
  180. });
  181. }
  182. return result;
  183. };
  184. // Hyperscript helper functions
  185. var same = function (vnode1, vnode2) {
  186. if (vnode1.vnodeSelector !== vnode2.vnodeSelector) {
  187. return false;
  188. }
  189. if (vnode1.properties && vnode2.properties) {
  190. if (vnode1.properties.key !== vnode2.properties.key) {
  191. return false;
  192. }
  193. return vnode1.properties.bind === vnode2.properties.bind;
  194. }
  195. return !vnode1.properties && !vnode2.properties;
  196. };
  197. var toTextVNode = function (data) {
  198. return {
  199. vnodeSelector: '',
  200. properties: undefined,
  201. children: undefined,
  202. text: data.toString(),
  203. domNode: null
  204. };
  205. };
  206. var appendChildren = function (parentSelector, insertions, main) {
  207. for (var i = 0; i < insertions.length; i++) {
  208. var item = insertions[i];
  209. if (Array.isArray(item)) {
  210. appendChildren(parentSelector, item, main);
  211. } else {
  212. if (item !== null && item !== undefined) {
  213. if (!item.hasOwnProperty('vnodeSelector')) {
  214. item = toTextVNode(item);
  215. }
  216. main.push(item);
  217. }
  218. }
  219. }
  220. };
  221. // Render helper functions
  222. var missingTransition = function () {
  223. throw new Error('Provide a transitions object to the projectionOptions to do animations');
  224. };
  225. var DEFAULT_PROJECTION_OPTIONS = {
  226. namespace: undefined,
  227. eventHandlerInterceptor: undefined,
  228. styleApplyer: function (domNode, styleName, value) {
  229. // Provides a hook to add vendor prefixes for browsers that still need it.
  230. domNode.style[styleName] = value;
  231. },
  232. transitions: {
  233. enter: missingTransition,
  234. exit: missingTransition
  235. }
  236. };
  237. var applyDefaultProjectionOptions = function (projectorOptions) {
  238. return extend(DEFAULT_PROJECTION_OPTIONS, projectorOptions);
  239. };
  240. var checkStyleValue = function (styleValue) {
  241. if (typeof styleValue !== 'string') {
  242. throw new Error('Style values must be strings');
  243. }
  244. };
  245. var setProperties = function (domNode, properties, projectionOptions) {
  246. if (!properties) {
  247. return;
  248. }
  249. var eventHandlerInterceptor = projectionOptions.eventHandlerInterceptor;
  250. var propNames = Object.keys(properties);
  251. var propCount = propNames.length;
  252. for (var i = 0; i < propCount; i++) {
  253. var propName = propNames[i];
  254. /* tslint:disable:no-var-keyword: edge case */
  255. var propValue = properties[propName];
  256. /* tslint:enable:no-var-keyword */
  257. if (propName === 'className') {
  258. throw new Error('Property "className" is not supported, use "class".');
  259. } else if (propName === 'class') {
  260. if (domNode.className) {
  261. // May happen if classes is specified before class
  262. domNode.className += ' ' + propValue;
  263. } else {
  264. domNode.className = propValue;
  265. }
  266. } else if (propName === 'classes') {
  267. // object with string keys and boolean values
  268. var classNames = Object.keys(propValue);
  269. var classNameCount = classNames.length;
  270. for (var j = 0; j < classNameCount; j++) {
  271. var className = classNames[j];
  272. if (propValue[className]) {
  273. domNode.classList.add(className);
  274. }
  275. }
  276. } else if (propName === 'styles') {
  277. // object with string keys and string (!) values
  278. var styleNames = Object.keys(propValue);
  279. var styleCount = styleNames.length;
  280. for (var j = 0; j < styleCount; j++) {
  281. var styleName = styleNames[j];
  282. var styleValue = propValue[styleName];
  283. if (styleValue) {
  284. checkStyleValue(styleValue);
  285. projectionOptions.styleApplyer(domNode, styleName, styleValue);
  286. }
  287. }
  288. } else if (propName === 'key') {
  289. continue;
  290. } else if (propValue === null || propValue === undefined) {
  291. continue;
  292. } else {
  293. var type = typeof propValue;
  294. if (type === 'function') {
  295. if (propName.lastIndexOf('on', 0) === 0) {
  296. if (eventHandlerInterceptor) {
  297. propValue = eventHandlerInterceptor(propName, propValue, domNode, properties); // intercept eventhandlers
  298. }
  299. if (propName === 'oninput') {
  300. (function () {
  301. // record the evt.target.value, because IE and Edge sometimes do a requestAnimationFrame between changing value and running oninput
  302. var oldPropValue = propValue;
  303. propValue = function (evt) {
  304. evt.target['oninput-value'] = evt.target.value;
  305. // may be HTMLTextAreaElement as well
  306. oldPropValue.apply(this, [evt]);
  307. };
  308. }());
  309. }
  310. domNode[propName] = propValue;
  311. }
  312. } else if (type === 'string' && propName !== 'value' && propName !== 'innerHTML') {
  313. if (projectionOptions.namespace === NAMESPACE_SVG && propName === 'href') {
  314. domNode.setAttributeNS(NAMESPACE_XLINK, propName, propValue);
  315. } else {
  316. domNode.setAttribute(propName, propValue);
  317. }
  318. } else {
  319. domNode[propName] = propValue;
  320. }
  321. }
  322. }
  323. };
  324. var updateProperties = function (domNode, previousProperties, properties, projectionOptions) {
  325. if (!properties) {
  326. return;
  327. }
  328. var propertiesUpdated = false;
  329. var propNames = Object.keys(properties);
  330. var propCount = propNames.length;
  331. for (var i = 0; i < propCount; i++) {
  332. var propName = propNames[i];
  333. // assuming that properties will be nullified instead of missing is by design
  334. var propValue = properties[propName];
  335. var previousValue = previousProperties[propName];
  336. if (propName === 'class') {
  337. if (previousValue !== propValue) {
  338. throw new Error('"class" property may not be updated. Use the "classes" property for conditional css classes.');
  339. }
  340. } else if (propName === 'classes') {
  341. var classList = domNode.classList;
  342. var classNames = Object.keys(propValue);
  343. var classNameCount = classNames.length;
  344. for (var j = 0; j < classNameCount; j++) {
  345. var className = classNames[j];
  346. var on = !!propValue[className];
  347. var previousOn = !!previousValue[className];
  348. if (on === previousOn) {
  349. continue;
  350. }
  351. propertiesUpdated = true;
  352. if (on) {
  353. classList.add(className);
  354. } else {
  355. classList.remove(className);
  356. }
  357. }
  358. } else if (propName === 'styles') {
  359. var styleNames = Object.keys(propValue);
  360. var styleCount = styleNames.length;
  361. for (var j = 0; j < styleCount; j++) {
  362. var styleName = styleNames[j];
  363. var newStyleValue = propValue[styleName];
  364. var oldStyleValue = previousValue[styleName];
  365. if (newStyleValue === oldStyleValue) {
  366. continue;
  367. }
  368. propertiesUpdated = true;
  369. if (newStyleValue) {
  370. checkStyleValue(newStyleValue);
  371. projectionOptions.styleApplyer(domNode, styleName, newStyleValue);
  372. } else {
  373. projectionOptions.styleApplyer(domNode, styleName, '');
  374. }
  375. }
  376. } else {
  377. if (!propValue && typeof previousValue === 'string') {
  378. propValue = '';
  379. }
  380. if (propName === 'value') {
  381. if (domNode[propName] !== propValue && domNode['oninput-value'] !== propValue) {
  382. domNode[propName] = propValue;
  383. // Reset the value, even if the virtual DOM did not change
  384. domNode['oninput-value'] = undefined;
  385. }
  386. // else do not update the domNode, otherwise the cursor position would be changed
  387. if (propValue !== previousValue) {
  388. propertiesUpdated = true;
  389. }
  390. } else if (propValue !== previousValue) {
  391. var type = typeof propValue;
  392. if (type === 'function') {
  393. throw new Error('Functions may not be updated on subsequent renders (property: ' + propName + '). Hint: declare event handler functions outside the render() function.');
  394. }
  395. if (type === 'string' && propName !== 'innerHTML') {
  396. if (projectionOptions.namespace === NAMESPACE_SVG && propName === 'href') {
  397. domNode.setAttributeNS(NAMESPACE_XLINK, propName, propValue);
  398. } else {
  399. domNode.setAttribute(propName, propValue);
  400. }
  401. } else {
  402. if (domNode[propName] !== propValue) {
  403. domNode[propName] = propValue;
  404. }
  405. }
  406. propertiesUpdated = true;
  407. }
  408. }
  409. }
  410. return propertiesUpdated;
  411. };
  412. var findIndexOfChild = function (children, sameAs, start) {
  413. if (sameAs.vnodeSelector !== '') {
  414. // Never scan for text-nodes
  415. for (var i = start; i < children.length; i++) {
  416. if (same(children[i], sameAs)) {
  417. return i;
  418. }
  419. }
  420. }
  421. return -1;
  422. };
  423. var nodeAdded = function (vNode, transitions) {
  424. if (vNode.properties) {
  425. var enterAnimation = vNode.properties.enterAnimation;
  426. if (enterAnimation) {
  427. if (typeof enterAnimation === 'function') {
  428. enterAnimation(vNode.domNode, vNode.properties);
  429. } else {
  430. transitions.enter(vNode.domNode, vNode.properties, enterAnimation);
  431. }
  432. }
  433. }
  434. };
  435. var nodeToRemove = function (vNode, transitions) {
  436. var domNode = vNode.domNode;
  437. if (vNode.properties) {
  438. var exitAnimation = vNode.properties.exitAnimation;
  439. if (exitAnimation) {
  440. domNode.style.pointerEvents = 'none';
  441. var removeDomNode = function () {
  442. if (domNode.parentNode) {
  443. domNode.parentNode.removeChild(domNode);
  444. }
  445. };
  446. if (typeof exitAnimation === 'function') {
  447. exitAnimation(domNode, removeDomNode, vNode.properties);
  448. return;
  449. } else {
  450. transitions.exit(vNode.domNode, vNode.properties, exitAnimation, removeDomNode);
  451. return;
  452. }
  453. }
  454. }
  455. if (domNode.parentNode) {
  456. domNode.parentNode.removeChild(domNode);
  457. }
  458. };
  459. var checkDistinguishable = function (childNodes, indexToCheck, parentVNode, operation) {
  460. var childNode = childNodes[indexToCheck];
  461. if (childNode.vnodeSelector === '') {
  462. return; // Text nodes need not be distinguishable
  463. }
  464. var properties = childNode.properties;
  465. var key = properties ? properties.key === undefined ? properties.bind : properties.key : undefined;
  466. if (!key) {
  467. for (var i = 0; i < childNodes.length; i++) {
  468. if (i !== indexToCheck) {
  469. var node = childNodes[i];
  470. if (same(node, childNode)) {
  471. if (operation === 'added') {
  472. throw new Error(parentVNode.vnodeSelector + ' had a ' + childNode.vnodeSelector + ' child ' + 'added, but there is now more than one. You must add unique key properties to make them distinguishable.');
  473. } else {
  474. throw new Error(parentVNode.vnodeSelector + ' had a ' + childNode.vnodeSelector + ' child ' + 'removed, but there were more than one. You must add unique key properties to make them distinguishable.');
  475. }
  476. }
  477. }
  478. }
  479. }
  480. };
  481. var createDom;
  482. var updateDom;
  483. var updateChildren = function (vnode, domNode, oldChildren, newChildren, projectionOptions) {
  484. if (oldChildren === newChildren) {
  485. return false;
  486. }
  487. oldChildren = oldChildren || emptyArray;
  488. newChildren = newChildren || emptyArray;
  489. var oldChildrenLength = oldChildren.length;
  490. var newChildrenLength = newChildren.length;
  491. var transitions = projectionOptions.transitions;
  492. var oldIndex = 0;
  493. var newIndex = 0;
  494. var i;
  495. var textUpdated = false;
  496. while (newIndex < newChildrenLength) {
  497. var oldChild = oldIndex < oldChildrenLength ? oldChildren[oldIndex] : undefined;
  498. var newChild = newChildren[newIndex];
  499. if (oldChild !== undefined && same(oldChild, newChild)) {
  500. textUpdated = updateDom(oldChild, newChild, projectionOptions) || textUpdated;
  501. oldIndex++;
  502. } else {
  503. var findOldIndex = findIndexOfChild(oldChildren, newChild, oldIndex + 1);
  504. if (findOldIndex >= 0) {
  505. // Remove preceding missing children
  506. for (i = oldIndex; i < findOldIndex; i++) {
  507. nodeToRemove(oldChildren[i], transitions);
  508. checkDistinguishable(oldChildren, i, vnode, 'removed');
  509. }
  510. textUpdated = updateDom(oldChildren[findOldIndex], newChild, projectionOptions) || textUpdated;
  511. oldIndex = findOldIndex + 1;
  512. } else {
  513. // New child
  514. createDom(newChild, domNode, oldIndex < oldChildrenLength ? oldChildren[oldIndex].domNode : undefined, projectionOptions);
  515. nodeAdded(newChild, transitions);
  516. checkDistinguishable(newChildren, newIndex, vnode, 'added');
  517. }
  518. }
  519. newIndex++;
  520. }
  521. if (oldChildrenLength > oldIndex) {
  522. // Remove child fragments
  523. for (i = oldIndex; i < oldChildrenLength; i++) {
  524. nodeToRemove(oldChildren[i], transitions);
  525. checkDistinguishable(oldChildren, i, vnode, 'removed');
  526. }
  527. }
  528. return textUpdated;
  529. };
  530. var addChildren = function (domNode, children, projectionOptions) {
  531. if (!children) {
  532. return;
  533. }
  534. for (var i = 0; i < children.length; i++) {
  535. createDom(children[i], domNode, undefined, projectionOptions);
  536. }
  537. };
  538. var initPropertiesAndChildren = function (domNode, vnode, projectionOptions) {
  539. addChildren(domNode, vnode.children, projectionOptions);
  540. // children before properties, needed for value property of <select>.
  541. if (vnode.text) {
  542. domNode.textContent = vnode.text;
  543. }
  544. setProperties(domNode, vnode.properties, projectionOptions);
  545. if (vnode.properties && vnode.properties.afterCreate) {
  546. vnode.properties.afterCreate(domNode, projectionOptions, vnode.vnodeSelector, vnode.properties, vnode.children);
  547. }
  548. };
  549. createDom = function (vnode, parentNode, insertBefore, projectionOptions) {
  550. var domNode, i, c, start = 0, type, found;
  551. var vnodeSelector = vnode.vnodeSelector;
  552. if (vnodeSelector === '') {
  553. domNode = vnode.domNode = document.createTextNode(vnode.text);
  554. if (insertBefore !== undefined) {
  555. parentNode.insertBefore(domNode, insertBefore);
  556. } else {
  557. parentNode.appendChild(domNode);
  558. }
  559. } else {
  560. for (i = 0; i <= vnodeSelector.length; ++i) {
  561. c = vnodeSelector.charAt(i);
  562. if (i === vnodeSelector.length || c === '.' || c === '#') {
  563. type = vnodeSelector.charAt(start - 1);
  564. found = vnodeSelector.slice(start, i);
  565. if (type === '.') {
  566. domNode.classList.add(found);
  567. } else if (type === '#') {
  568. domNode.id = found;
  569. } else {
  570. if (found === 'svg') {
  571. projectionOptions = extend(projectionOptions, { namespace: NAMESPACE_SVG });
  572. }
  573. if (projectionOptions.namespace !== undefined) {
  574. domNode = vnode.domNode = document.createElementNS(projectionOptions.namespace, found);
  575. } else {
  576. domNode = vnode.domNode = document.createElement(found);
  577. }
  578. if (insertBefore !== undefined) {
  579. parentNode.insertBefore(domNode, insertBefore);
  580. } else {
  581. parentNode.appendChild(domNode);
  582. }
  583. }
  584. start = i + 1;
  585. }
  586. }
  587. initPropertiesAndChildren(domNode, vnode, projectionOptions);
  588. }
  589. };
  590. updateDom = function (previous, vnode, projectionOptions) {
  591. var domNode = previous.domNode;
  592. var textUpdated = false;
  593. if (previous === vnode) {
  594. return false; // By contract, VNode objects may not be modified anymore after passing them to maquette
  595. }
  596. var updated = false;
  597. if (vnode.vnodeSelector === '') {
  598. if (vnode.text !== previous.text) {
  599. var newVNode = document.createTextNode(vnode.text);
  600. domNode.parentNode.replaceChild(newVNode, domNode);
  601. vnode.domNode = newVNode;
  602. textUpdated = true;
  603. return textUpdated;
  604. }
  605. } else {
  606. if (vnode.vnodeSelector.lastIndexOf('svg', 0) === 0) {
  607. projectionOptions = extend(projectionOptions, { namespace: NAMESPACE_SVG });
  608. }
  609. if (previous.text !== vnode.text) {
  610. updated = true;
  611. if (vnode.text === undefined) {
  612. domNode.removeChild(domNode.firstChild); // the only textnode presumably
  613. } else {
  614. domNode.textContent = vnode.text;
  615. }
  616. }
  617. updated = updateChildren(vnode, domNode, previous.children, vnode.children, projectionOptions) || updated;
  618. updated = updateProperties(domNode, previous.properties, vnode.properties, projectionOptions) || updated;
  619. if (vnode.properties && vnode.properties.afterUpdate) {
  620. vnode.properties.afterUpdate(domNode, projectionOptions, vnode.vnodeSelector, vnode.properties, vnode.children);
  621. }
  622. }
  623. if (updated && vnode.properties && vnode.properties.updateAnimation) {
  624. vnode.properties.updateAnimation(domNode, vnode.properties, previous.properties);
  625. }
  626. vnode.domNode = previous.domNode;
  627. return textUpdated;
  628. };
  629. var createProjection = function (vnode, projectionOptions) {
  630. return {
  631. update: function (updatedVnode) {
  632. if (vnode.vnodeSelector !== updatedVnode.vnodeSelector) {
  633. throw new Error('The selector for the root VNode may not be changed. (consider using dom.merge and add one extra level to the virtual DOM)');
  634. }
  635. updateDom(vnode, updatedVnode, projectionOptions);
  636. vnode = updatedVnode;
  637. },
  638. domNode: vnode.domNode
  639. };
  640. };
  641. ;
  642. // The other two parameters are not added here, because the Typescript compiler creates surrogate code for desctructuring 'children'.
  643. exports.h = function (selector) {
  644. var properties = arguments[1];
  645. if (typeof selector !== 'string') {
  646. throw new Error();
  647. }
  648. var childIndex = 1;
  649. if (properties && !properties.hasOwnProperty('vnodeSelector') && !Array.isArray(properties) && typeof properties === 'object') {
  650. childIndex = 2;
  651. } else {
  652. // Optional properties argument was omitted
  653. properties = undefined;
  654. }
  655. var text = undefined;
  656. var children = undefined;
  657. var argsLength = arguments.length;
  658. // Recognize a common special case where there is only a single text node
  659. if (argsLength === childIndex + 1) {
  660. var onlyChild = arguments[childIndex];
  661. if (typeof onlyChild === 'string') {
  662. text = onlyChild;
  663. } else if (onlyChild !== undefined && onlyChild.length === 1 && typeof onlyChild[0] === 'string') {
  664. text = onlyChild[0];
  665. }
  666. }
  667. if (text === undefined) {
  668. children = [];
  669. for (; childIndex < arguments.length; childIndex++) {
  670. var child = arguments[childIndex];
  671. if (child === null || child === undefined) {
  672. continue;
  673. } else if (Array.isArray(child)) {
  674. appendChildren(selector, child, children);
  675. } else if (child.hasOwnProperty('vnodeSelector')) {
  676. children.push(child);
  677. } else {
  678. children.push(toTextVNode(child));
  679. }
  680. }
  681. }
  682. return {
  683. vnodeSelector: selector,
  684. properties: properties,
  685. children: children,
  686. text: text === '' ? undefined : text,
  687. domNode: null
  688. };
  689. };
  690. /**
  691. * Contains simple low-level utility functions to manipulate the real DOM.
  692. */
  693. exports.dom = {
  694. /**
  695. * Creates a real DOM tree from `vnode`. The [[Projection]] object returned will contain the resulting DOM Node in
  696. * its [[Projection.domNode|domNode]] property.
  697. * This is a low-level method. Users wil typically use a [[Projector]] instead.
  698. * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]]
  699. * objects may only be rendered once.
  700. * @param projectionOptions - Options to be used to create and update the projection.
  701. * @returns The [[Projection]] which also contains the DOM Node that was created.
  702. */
  703. create: function (vnode, projectionOptions) {
  704. projectionOptions = applyDefaultProjectionOptions(projectionOptions);
  705. createDom(vnode, document.createElement('div'), undefined, projectionOptions);
  706. return createProjection(vnode, projectionOptions);
  707. },
  708. /**
  709. * Appends a new childnode to the DOM which is generated from a [[VNode]].
  710. * This is a low-level method. Users wil typically use a [[Projector]] instead.
  711. * @param parentNode - The parent node for the new childNode.
  712. * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]]
  713. * objects may only be rendered once.
  714. * @param projectionOptions - Options to be used to create and update the [[Projection]].
  715. * @returns The [[Projection]] that was created.
  716. */
  717. append: function (parentNode, vnode, projectionOptions) {
  718. projectionOptions = applyDefaultProjectionOptions(projectionOptions);
  719. createDom(vnode, parentNode, undefined, projectionOptions);
  720. return createProjection(vnode, projectionOptions);
  721. },
  722. /**
  723. * Inserts a new DOM node which is generated from a [[VNode]].
  724. * This is a low-level method. Users wil typically use a [[Projector]] instead.
  725. * @param beforeNode - The node that the DOM Node is inserted before.
  726. * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function.
  727. * NOTE: [[VNode]] objects may only be rendered once.
  728. * @param projectionOptions - Options to be used to create and update the projection, see [[createProjector]].
  729. * @returns The [[Projection]] that was created.
  730. */
  731. insertBefore: function (beforeNode, vnode, projectionOptions) {
  732. projectionOptions = applyDefaultProjectionOptions(projectionOptions);
  733. createDom(vnode, beforeNode.parentNode, beforeNode, projectionOptions);
  734. return createProjection(vnode, projectionOptions);
  735. },
  736. /**
  737. * Merges a new DOM node which is generated from a [[VNode]] with an existing DOM Node.
  738. * This means that the virtual DOM and the real DOM will have one overlapping element.
  739. * Therefore the selector for the root [[VNode]] will be ignored, but its properties and children will be applied to the Element provided.
  740. * This is a low-level method. Users wil typically use a [[Projector]] instead.
  741. * @param domNode - The existing element to adopt as the root of the new virtual DOM. Existing attributes and childnodes are preserved.
  742. * @param vnode - The root of the virtual DOM tree that was created using the [[h]] function. NOTE: [[VNode]] objects
  743. * may only be rendered once.
  744. * @param projectionOptions - Options to be used to create and update the projection, see [[createProjector]].
  745. * @returns The [[Projection]] that was created.
  746. */
  747. merge: function (element, vnode, projectionOptions) {
  748. projectionOptions = applyDefaultProjectionOptions(projectionOptions);
  749. vnode.domNode = element;
  750. initPropertiesAndChildren(element, vnode, projectionOptions);
  751. return createProjection(vnode, projectionOptions);
  752. }
  753. };
  754. /**
  755. * Creates a [[CalculationCache]] object, useful for caching [[VNode]] trees.
  756. * In practice, caching of [[VNode]] trees is not needed, because achieving 60 frames per second is almost never a problem.
  757. * For more information, see [[CalculationCache]].
  758. *
  759. * @param <Result> The type of the value that is cached.
  760. */
  761. exports.createCache = function () {
  762. var cachedInputs = undefined;
  763. var cachedOutcome = undefined;
  764. var result = {
  765. invalidate: function () {
  766. cachedOutcome = undefined;
  767. cachedInputs = undefined;
  768. },
  769. result: function (inputs, calculation) {
  770. if (cachedInputs) {
  771. for (var i = 0; i < inputs.length; i++) {
  772. if (cachedInputs[i] !== inputs[i]) {
  773. cachedOutcome = undefined;
  774. }
  775. }
  776. }
  777. if (!cachedOutcome) {
  778. cachedOutcome = calculation();
  779. cachedInputs = inputs;
  780. }
  781. return cachedOutcome;
  782. }
  783. };
  784. return result;
  785. };
  786. /**
  787. * Creates a {@link Mapping} instance that keeps an array of result objects synchronized with an array of source objects.
  788. * See {@link http://maquettejs.org/docs/arrays.html|Working with arrays}.
  789. *
  790. * @param <Source> The type of source items. A database-record for instance.
  791. * @param <Target> The type of target items. A [[Component]] for instance.
  792. * @param getSourceKey `function(source)` that must return a key to identify each source object. The result must either be a string or a number.
  793. * @param createResult `function(source, index)` that must create a new result object from a given source. This function is identical
  794. * to the `callback` argument in `Array.map(callback)`.
  795. * @param updateResult `function(source, target, index)` that updates a result to an updated source.
  796. */
  797. exports.createMapping = function (getSourceKey, createResult, updateResult) {
  798. var keys = [];
  799. var results = [];
  800. return {
  801. results: results,
  802. map: function (newSources) {
  803. var newKeys = newSources.map(getSourceKey);
  804. var oldTargets = results.slice();
  805. var oldIndex = 0;
  806. for (var i = 0; i < newSources.length; i++) {
  807. var source = newSources[i];
  808. var sourceKey = newKeys[i];
  809. if (sourceKey === keys[oldIndex]) {
  810. results[i] = oldTargets[oldIndex];
  811. updateResult(source, oldTargets[oldIndex], i);
  812. oldIndex++;
  813. } else {
  814. var found = false;
  815. for (var j = 1; j < keys.length; j++) {
  816. var searchIndex = (oldIndex + j) % keys.length;
  817. if (keys[searchIndex] === sourceKey) {
  818. results[i] = oldTargets[searchIndex];
  819. updateResult(newSources[i], oldTargets[searchIndex], i);
  820. oldIndex = searchIndex + 1;
  821. found = true;
  822. break;
  823. }
  824. }
  825. if (!found) {
  826. results[i] = createResult(source, i);
  827. }
  828. }
  829. }
  830. results.length = newSources.length;
  831. keys = newKeys;
  832. }
  833. };
  834. };
  835. /**
  836. * Creates a [[Projector]] instance using the provided projectionOptions.
  837. *
  838. * For more information, see [[Projector]].
  839. *
  840. * @param projectionOptions Options that influence how the DOM is rendered and updated.
  841. */
  842. exports.createProjector = function (projectorOptions) {
  843. var projector;
  844. var projectionOptions = applyDefaultProjectionOptions(projectorOptions);
  845. projectionOptions.eventHandlerInterceptor = function (propertyName, eventHandler, domNode, properties) {
  846. return function () {
  847. // intercept function calls (event handlers) to do a render afterwards.
  848. projector.scheduleRender();
  849. return eventHandler.apply(properties.bind || this, arguments);
  850. };
  851. };
  852. var renderCompleted = true;
  853. var scheduled;
  854. var stopped = false;
  855. var projections = [];
  856. var renderFunctions = [];
  857. // matches the projections array
  858. var doRender = function () {
  859. scheduled = undefined;
  860. if (!renderCompleted) {
  861. return; // The last render threw an error, it should be logged in the browser console.
  862. }
  863. renderCompleted = false;
  864. for (var i = 0; i < projections.length; i++) {
  865. var updatedVnode = renderFunctions[i]();
  866. projections[i].update(updatedVnode);
  867. }
  868. renderCompleted = true;
  869. };
  870. projector = {
  871. scheduleRender: function () {
  872. if (!scheduled && !stopped) {
  873. scheduled = requestAnimationFrame(doRender);
  874. }
  875. },
  876. stop: function () {
  877. if (scheduled) {
  878. cancelAnimationFrame(scheduled);
  879. scheduled = undefined;
  880. }
  881. stopped = true;
  882. },
  883. resume: function () {
  884. stopped = false;
  885. renderCompleted = true;
  886. projector.scheduleRender();
  887. },
  888. append: function (parentNode, renderMaquetteFunction) {
  889. projections.push(exports.dom.append(parentNode, renderMaquetteFunction(), projectionOptions));
  890. renderFunctions.push(renderMaquetteFunction);
  891. },
  892. insertBefore: function (beforeNode, renderMaquetteFunction) {
  893. projections.push(exports.dom.insertBefore(beforeNode, renderMaquetteFunction(), projectionOptions));
  894. renderFunctions.push(renderMaquetteFunction);
  895. },
  896. merge: function (domNode, renderMaquetteFunction) {
  897. projections.push(exports.dom.merge(domNode, renderMaquetteFunction(), projectionOptions));
  898. renderFunctions.push(renderMaquetteFunction);
  899. },
  900. replace: function (domNode, renderMaquetteFunction) {
  901. var vnode = renderMaquetteFunction();
  902. createDom(vnode, domNode.parentNode, domNode, projectionOptions);
  903. domNode.parentNode.removeChild(domNode);
  904. projections.push(createProjection(vnode, projectionOptions));
  905. renderFunctions.push(renderMaquetteFunction);
  906. },
  907. detach: function (renderMaquetteFunction) {
  908. for (var i = 0; i < renderFunctions.length; i++) {
  909. if (renderFunctions[i] === renderMaquetteFunction) {
  910. renderFunctions.splice(i, 1);
  911. return projections.splice(i, 1)[0];
  912. }
  913. }
  914. throw new Error('renderMaquetteFunction was not found');
  915. }
  916. };
  917. return projector;
  918. };
  919. }));
  920. /* ---- utils/Animation.coffee ---- */
  921. (function() {
  922. var Animation;
  923. Animation = (function() {
  924. function Animation() {}
  925. Animation.prototype.slideDown = function(elem, props) {
  926. var cstyle, h, margin_bottom, margin_top, padding_bottom, padding_top, transition;
  927. if (elem.offsetTop > 2000) {
  928. return;
  929. }
  930. h = elem.offsetHeight;
  931. cstyle = window.getComputedStyle(elem);
  932. margin_top = cstyle.marginTop;
  933. margin_bottom = cstyle.marginBottom;
  934. padding_top = cstyle.paddingTop;
  935. padding_bottom = cstyle.paddingBottom;
  936. transition = cstyle.transition;
  937. elem.style.boxSizing = "border-box";
  938. elem.style.overflow = "hidden";
  939. elem.style.transform = "scale(0.6)";
  940. elem.style.opacity = "0";
  941. elem.style.height = "0px";
  942. elem.style.marginTop = "0px";
  943. elem.style.marginBottom = "0px";
  944. elem.style.paddingTop = "0px";
  945. elem.style.paddingBottom = "0px";
  946. elem.style.transition = "none";
  947. setTimeout((function() {
  948. elem.className += " animate-inout";
  949. elem.style.height = h + "px";
  950. elem.style.transform = "scale(1)";
  951. elem.style.opacity = "1";
  952. elem.style.marginTop = margin_top;
  953. elem.style.marginBottom = margin_bottom;
  954. elem.style.paddingTop = padding_top;
  955. return elem.style.paddingBottom = padding_bottom;
  956. }), 1);
  957. return elem.addEventListener("transitionend", function() {
  958. elem.classList.remove("animate-inout");
  959. elem.style.transition = elem.style.transform = elem.style.opacity = elem.style.height = null;
  960. elem.style.boxSizing = elem.style.marginTop = elem.style.marginBottom = null;
  961. elem.style.paddingTop = elem.style.paddingBottom = elem.style.overflow = null;
  962. return elem.removeEventListener("transitionend", arguments.callee, false);
  963. });
  964. };
  965. Animation.prototype.slideUp = function(elem, remove_func, props) {
  966. if (elem.offsetTop > 1000) {
  967. return remove_func();
  968. }
  969. elem.className += " animate-back";
  970. elem.style.boxSizing = "border-box";
  971. elem.style.height = elem.offsetHeight + "px";
  972. elem.style.overflow = "hidden";
  973. elem.style.transform = "scale(1)";
  974. elem.style.opacity = "1";
  975. elem.style.pointerEvents = "none";
  976. setTimeout((function() {
  977. elem.style.height = "0px";
  978. elem.style.marginTop = "0px";
  979. elem.style.marginBottom = "0px";
  980. elem.style.paddingTop = "0px";
  981. elem.style.paddingBottom = "0px";
  982. elem.style.transform = "scale(0.8)";
  983. elem.style.borderTopWidth = "0px";
  984. elem.style.borderBottomWidth = "0px";
  985. return elem.style.opacity = "0";
  986. }), 1);
  987. return elem.addEventListener("transitionend", function(e) {
  988. if (e.propertyName === "opacity" || e.elapsedTime >= 0.6) {
  989. elem.removeEventListener("transitionend", arguments.callee, false);
  990. return remove_func();
  991. }
  992. });
  993. };
  994. Animation.prototype.slideUpInout = function(elem, remove_func, props) {
  995. elem.className += " animate-inout";
  996. elem.style.boxSizing = "border-box";
  997. elem.style.height = elem.offsetHeight + "px";
  998. elem.style.overflow = "hidden";
  999. elem.style.transform = "scale(1)";
  1000. elem.style.opacity = "1";
  1001. elem.style.pointerEvents = "none";
  1002. setTimeout((function() {
  1003. elem.style.height = "0px";
  1004. elem.style.marginTop = "0px";
  1005. elem.style.marginBottom = "0px";
  1006. elem.style.paddingTop = "0px";
  1007. elem.style.paddingBottom = "0px";
  1008. elem.style.transform = "scale(0.8)";
  1009. elem.style.borderTopWidth = "0px";
  1010. elem.style.borderBottomWidth = "0px";
  1011. return elem.style.opacity = "0";
  1012. }), 1);
  1013. return elem.addEventListener("transitionend", function(e) {
  1014. if (e.propertyName === "opacity" || e.elapsedTime >= 0.6) {
  1015. elem.removeEventListener("transitionend", arguments.callee, false);
  1016. return remove_func();
  1017. }
  1018. });
  1019. };
  1020. Animation.prototype.showRight = function(elem, props) {
  1021. elem.className += " animate";
  1022. elem.style.opacity = 0;
  1023. elem.style.transform = "TranslateX(-20px) Scale(1.01)";
  1024. setTimeout((function() {
  1025. elem.style.opacity = 1;
  1026. return elem.style.transform = "TranslateX(0px) Scale(1)";
  1027. }), 1);
  1028. return elem.addEventListener("transitionend", function() {
  1029. elem.classList.remove("animate");
  1030. return elem.style.transform = elem.style.opacity = null;
  1031. });
  1032. };
  1033. Animation.prototype.show = function(elem, props) {
  1034. var delay, ref;
  1035. delay = ((ref = arguments[arguments.length - 2]) != null ? ref.delay : void 0) * 1000 || 1;
  1036. elem.style.opacity = 0;
  1037. setTimeout((function() {
  1038. return elem.className += " animate";
  1039. }), 1);
  1040. setTimeout((function() {
  1041. return elem.style.opacity = 1;
  1042. }), delay);
  1043. return elem.addEventListener("transitionend", function() {
  1044. elem.classList.remove("animate");
  1045. elem.style.opacity = null;
  1046. return elem.removeEventListener("transitionend", arguments.callee, false);
  1047. });
  1048. };
  1049. Animation.prototype.hide = function(elem, remove_func, props) {
  1050. var delay, ref;
  1051. delay = ((ref = arguments[arguments.length - 2]) != null ? ref.delay : void 0) * 1000 || 1;
  1052. elem.className += " animate";
  1053. setTimeout((function() {
  1054. return elem.style.opacity = 0;
  1055. }), delay);
  1056. return elem.addEventListener("transitionend", function(e) {
  1057. if (e.propertyName === "opacity") {
  1058. return remove_func();
  1059. }
  1060. });
  1061. };
  1062. Animation.prototype.addVisibleClass = function(elem, props) {
  1063. return setTimeout(function() {
  1064. return elem.classList.add("visible");
  1065. });
  1066. };
  1067. return Animation;
  1068. })();
  1069. window.Animation = new Animation();
  1070. }).call(this);
  1071. /* ---- utils/Dollar.coffee ---- */
  1072. (function() {
  1073. window.$ = function(selector) {
  1074. if (selector.startsWith("#")) {
  1075. return document.getElementById(selector.replace("#", ""));
  1076. }
  1077. };
  1078. }).call(this);
  1079. /* ---- utils/ZeroFrame.coffee ---- */
  1080. (function() {
  1081. var ZeroFrame,
  1082. bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
  1083. extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  1084. hasProp = {}.hasOwnProperty;
  1085. ZeroFrame = (function(superClass) {
  1086. extend(ZeroFrame, superClass);
  1087. function ZeroFrame(url) {
  1088. this.onCloseWebsocket = bind(this.onCloseWebsocket, this);
  1089. this.onOpenWebsocket = bind(this.onOpenWebsocket, this);
  1090. this.onRequest = bind(this.onRequest, this);
  1091. this.onMessage = bind(this.onMessage, this);
  1092. this.url = url;
  1093. this.waiting_cb = {};
  1094. this.wrapper_nonce = document.location.href.replace(/.*wrapper_nonce=([A-Za-z0-9]+).*/, "$1");
  1095. this.connect();
  1096. this.next_message_id = 1;
  1097. this.history_state = {};
  1098. this.init();
  1099. }
  1100. ZeroFrame.prototype.init = function() {
  1101. return this;
  1102. };
  1103. ZeroFrame.prototype.connect = function() {
  1104. this.target = window.parent;
  1105. window.addEventListener("message", this.onMessage, false);
  1106. this.cmd("innerReady");
  1107. window.addEventListener("beforeunload", (function(_this) {
  1108. return function(e) {
  1109. _this.log("save scrollTop", window.pageYOffset);
  1110. _this.history_state["scrollTop"] = window.pageYOffset;
  1111. return _this.cmd("wrapperReplaceState", [_this.history_state, null]);
  1112. };
  1113. })(this));
  1114. return this.cmd("wrapperGetState", [], (function(_this) {
  1115. return function(state) {
  1116. if (state != null) {
  1117. _this.history_state = state;
  1118. }
  1119. _this.log("restore scrollTop", state, window.pageYOffset);
  1120. if (window.pageYOffset === 0 && state) {
  1121. return window.scroll(window.pageXOffset, state.scrollTop);
  1122. }
  1123. };
  1124. })(this));
  1125. };
  1126. ZeroFrame.prototype.onMessage = function(e) {
  1127. var cmd, message;
  1128. message = e.data;
  1129. cmd = message.cmd;
  1130. if (cmd === "response") {
  1131. if (this.waiting_cb[message.to] != null) {
  1132. return this.waiting_cb[message.to](message.result);
  1133. } else {
  1134. return this.log("Websocket callback not found:", message);
  1135. }
  1136. } else if (cmd === "wrapperReady") {
  1137. return this.cmd("innerReady");
  1138. } else if (cmd === "ping") {
  1139. return this.response(message.id, "pong");
  1140. } else if (cmd === "wrapperOpenedWebsocket") {
  1141. return this.onOpenWebsocket();
  1142. } else if (cmd === "wrapperClosedWebsocket") {
  1143. return this.onCloseWebsocket();
  1144. } else {
  1145. return this.onRequest(cmd, message.params);
  1146. }
  1147. };
  1148. ZeroFrame.prototype.onRequest = function(cmd, message) {
  1149. return this.log("Unknown request", message);
  1150. };
  1151. ZeroFrame.prototype.response = function(to, result) {
  1152. return this.send({
  1153. "cmd": "response",
  1154. "to": to,
  1155. "result": result
  1156. });
  1157. };
  1158. ZeroFrame.prototype.cmd = function(cmd, params, cb) {
  1159. if (params == null) {
  1160. params = {};
  1161. }
  1162. if (cb == null) {
  1163. cb = null;
  1164. }
  1165. return this.send({
  1166. "cmd": cmd,
  1167. "params": params
  1168. }, cb);
  1169. };
  1170. ZeroFrame.prototype.send = function(message, cb) {
  1171. if (cb == null) {
  1172. cb = null;
  1173. }
  1174. message.wrapper_nonce = this.wrapper_nonce;
  1175. message.id = this.next_message_id;
  1176. this.next_message_id += 1;
  1177. this.target.postMessage(message, "*");
  1178. if (cb) {
  1179. return this.waiting_cb[message.id] = cb;
  1180. }
  1181. };
  1182. ZeroFrame.prototype.onOpenWebsocket = function() {
  1183. return this.log("Websocket open");
  1184. };
  1185. ZeroFrame.prototype.onCloseWebsocket = function() {
  1186. return this.log("Websocket close");
  1187. };
  1188. return ZeroFrame;
  1189. })(Class);
  1190. window.ZeroFrame = ZeroFrame;
  1191. }).call(this);
  1192. /* ---- ConfigStorage.coffee ---- */
  1193. (function() {
  1194. var ConfigStorage,
  1195. bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
  1196. extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  1197. hasProp = {}.hasOwnProperty;
  1198. ConfigStorage = (function(superClass) {
  1199. extend(ConfigStorage, superClass);
  1200. function ConfigStorage(config) {
  1201. this.config = config;
  1202. this.createSection = bind(this.createSection, this);
  1203. this.items = [];
  1204. this.createSections();
  1205. this.setValues(this.config);
  1206. }
  1207. ConfigStorage.prototype.setValues = function(values) {
  1208. var i, item, len, ref, results, section;
  1209. ref = this.items;
  1210. results = [];
  1211. for (i = 0, len = ref.length; i < len; i++) {
  1212. section = ref[i];
  1213. results.push((function() {
  1214. var j, len1, ref1, results1;
  1215. ref1 = section.items;
  1216. results1 = [];
  1217. for (j = 0, len1 = ref1.length; j < len1; j++) {
  1218. item = ref1[j];
  1219. if (!values[item.key]) {
  1220. continue;
  1221. }
  1222. item.value = this.formatValue(values[item.key].value);
  1223. item["default"] = this.formatValue(values[item.key]["default"]);
  1224. item.pending = values[item.key].pending;
  1225. results1.push(values[item.key].item = item);
  1226. }
  1227. return results1;
  1228. }).call(this));
  1229. }
  1230. return results;
  1231. };
  1232. ConfigStorage.prototype.formatValue = function(value) {
  1233. if (!value) {
  1234. return false;
  1235. } else if (typeof value === "object") {
  1236. return value.join("\n");
  1237. } else if (typeof value === "number") {
  1238. return value.toString();
  1239. } else {
  1240. return value;
  1241. }
  1242. };
  1243. ConfigStorage.prototype.deformatValue = function(value, type) {
  1244. if (type === "object" && typeof value === "string") {
  1245. if (!value.length) {
  1246. return value = null;
  1247. } else {
  1248. return value.split("\n");
  1249. }
  1250. }
  1251. if (type === "boolean" && !value) {
  1252. return false;
  1253. } else if (type === "number") {
  1254. if (typeof value === "number") {
  1255. return value.toString();
  1256. } else if (!value) {
  1257. return "0";
  1258. } else {
  1259. return value;
  1260. }
  1261. } else {
  1262. return value;
  1263. }
  1264. };
  1265. ConfigStorage.prototype.createSections = function() {
  1266. var section;
  1267. section = this.createSection("Web Interface");
  1268. section.items.push({
  1269. key: "open_browser",
  1270. title: "Open web browser on ZeroNet startup",
  1271. type: "checkbox"
  1272. });
  1273. section = this.createSection("Network");
  1274. section.items.push({
  1275. key: "offline",
  1276. title: "Offline mode",
  1277. type: "checkbox",
  1278. description: "Disable network communication."
  1279. });
  1280. section.items.push({
  1281. key: "fileserver_ip_type",
  1282. title: "File server network",
  1283. type: "select",
  1284. options: [
  1285. {
  1286. title: "IPv4",
  1287. value: "ipv4"
  1288. }, {
  1289. title: "IPv6",
  1290. value: "ipv6"
  1291. }, {
  1292. title: "Dual (IPv4 & IPv6)",
  1293. value: "dual"
  1294. }
  1295. ],
  1296. description: "Accept incoming peers using IPv4 or IPv6 address. (default: dual)"
  1297. });
  1298. section.items.push({
  1299. key: "fileserver_port",
  1300. title: "File server port",
  1301. type: "text",
  1302. valid_pattern: /[0-9]*/,
  1303. description: "Other peers will use this port to reach your served sites. (default: randomize)"
  1304. });
  1305. section.items.push({
  1306. key: "ip_external",
  1307. title: "File server external ip",
  1308. type: "textarea",
  1309. placeholder: "Detect automatically",
  1310. description: "Your file server is accessible on these ips. (default: detect automatically)"
  1311. });
  1312. section.items.push({
  1313. title: "Tor",
  1314. key: "tor",
  1315. type: "select",
  1316. options: [
  1317. {
  1318. title: "Disable",
  1319. value: "disable"
  1320. }, {
  1321. title: "Enable",
  1322. value: "enable"
  1323. }, {
  1324. title: "Always",
  1325. value: "always"
  1326. }
  1327. ],
  1328. description: ["Disable: Don't connect to peers on Tor network", h("br"), "Enable: Only use Tor for Tor network peers", h("br"), "Always: Use Tor for every connections to hide your IP address (slower)"]
  1329. });
  1330. section.items.push({
  1331. title: "Use Tor bridges",
  1332. key: "tor_use_bridges",
  1333. type: "checkbox",
  1334. description: "Use obfuscated bridge relays to avoid network level Tor block (even slower)",
  1335. isHidden: function() {
  1336. return !Page.server_info.tor_has_meek_bridges;
  1337. }
  1338. });
  1339. section.items.push({
  1340. title: "Trackers",
  1341. key: "trackers",
  1342. type: "textarea",
  1343. description: "Discover new peers using these adresses"
  1344. });
  1345. section.items.push({
  1346. title: "Trackers files",
  1347. key: "trackers_file",
  1348. type: "textarea",
  1349. description: "Load additional list of torrent trackers dynamically, from a file",
  1350. placeholder: "Eg.: {data_dir}/trackers.json",
  1351. value_pos: "fullwidth"
  1352. });
  1353. section.items.push({
  1354. title: "Proxy for tracker connections",
  1355. key: "trackers_proxy",
  1356. type: "select",
  1357. options: [
  1358. {
  1359. title: "Custom",
  1360. value: ""
  1361. }, {
  1362. title: "Tor",
  1363. value: "tor"
  1364. }, {
  1365. title: "Disable",
  1366. value: "disable"
  1367. }
  1368. ],
  1369. isHidden: function() {
  1370. return Page.values["tor"] === "always";
  1371. }
  1372. });
  1373. section.items.push({
  1374. title: "Custom socks proxy address for trackers",
  1375. key: "trackers_proxy",
  1376. type: "text",
  1377. placeholder: "Eg.: 127.0.0.1:1080",
  1378. value_pos: "fullwidth",
  1379. valid_pattern: /.+:[0-9]+/,
  1380. isHidden: (function(_this) {
  1381. return function() {
  1382. var ref;
  1383. return (ref = Page.values["trackers_proxy"]) === "tor" || ref === "disable";
  1384. };
  1385. })(this)
  1386. });
  1387. section = this.createSection("Performance");
  1388. section.items.push({
  1389. key: "log_level",
  1390. title: "Level of logging to file",
  1391. type: "select",
  1392. options: [
  1393. {
  1394. title: "Everything",
  1395. value: "DEBUG"
  1396. }, {
  1397. title: "Only important messages",
  1398. value: "INFO"
  1399. }, {
  1400. title: "Only errors",
  1401. value: "ERROR"
  1402. }
  1403. ]
  1404. });
  1405. section.items.push({
  1406. key: "threads_fs_read",
  1407. title: "Threads for async file system reads",
  1408. type: "select",
  1409. options: [
  1410. {
  1411. title: "Sync read",
  1412. value: 0
  1413. }, {
  1414. title: "1 thread",
  1415. value: 1
  1416. }, {
  1417. title: "2 threads",
  1418. value: 2
  1419. }, {
  1420. title: "3 threads",
  1421. value: 3
  1422. }, {
  1423. title: "4 threads",
  1424. value: 4
  1425. }, {
  1426. title: "5 threads",
  1427. value: 5
  1428. }, {
  1429. title: "10 threads",
  1430. value: 10
  1431. }
  1432. ]
  1433. });
  1434. section.items.push({
  1435. key: "threads_fs_write",
  1436. title: "Threads for async file system writes",
  1437. type: "select",
  1438. options: [
  1439. {
  1440. title: "Sync write",
  1441. value: 0
  1442. }, {
  1443. title: "1 thread",
  1444. value: 1
  1445. }, {
  1446. title: "2 threads",
  1447. value: 2
  1448. }, {
  1449. title: "3 threads",
  1450. value: 3
  1451. }, {
  1452. title: "4 threads",
  1453. value: 4
  1454. }, {
  1455. title: "5 threads",
  1456. value: 5
  1457. }, {
  1458. title: "10 threads",
  1459. value: 10
  1460. }
  1461. ]
  1462. });
  1463. section.items.push({
  1464. key: "threads_crypt",
  1465. title: "Threads for cryptographic functions",
  1466. type: "select",
  1467. options: [
  1468. {
  1469. title: "Sync execution",
  1470. value: 0
  1471. }, {
  1472. title: "1 thread",
  1473. value: 1
  1474. }, {
  1475. title: "2 threads",
  1476. value: 2
  1477. }, {
  1478. title: "3 threads",
  1479. value: 3
  1480. }, {
  1481. title: "4 threads",
  1482. value: 4
  1483. }, {
  1484. title: "5 threads",
  1485. value: 5
  1486. }, {
  1487. title: "10 threads",
  1488. value: 10
  1489. }
  1490. ]
  1491. });
  1492. return section.items.push({
  1493. key: "threads_db",
  1494. title: "Threads for database operations",
  1495. type: "select",
  1496. options: [
  1497. {
  1498. title: "Sync execution",
  1499. value: 0
  1500. }, {
  1501. title: "1 thread",
  1502. value: 1
  1503. }, {
  1504. title: "2 threads",
  1505. value: 2
  1506. }, {
  1507. title: "3 threads",
  1508. value: 3
  1509. }, {
  1510. title: "4 threads",
  1511. value: 4
  1512. }, {
  1513. title: "5 threads",
  1514. value: 5
  1515. }, {
  1516. title: "10 threads",
  1517. value: 10
  1518. }
  1519. ]
  1520. });
  1521. };
  1522. ConfigStorage.prototype.createSection = function(title) {
  1523. var section;
  1524. section = {};
  1525. section.title = title;
  1526. section.items = [];
  1527. this.items.push(section);
  1528. return section;
  1529. };
  1530. return ConfigStorage;
  1531. })(Class);
  1532. window.ConfigStorage = ConfigStorage;
  1533. }).call(this);
  1534. /* ---- ConfigView.coffee ---- */
  1535. (function() {
  1536. var ConfigView,
  1537. bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
  1538. extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  1539. hasProp = {}.hasOwnProperty;
  1540. ConfigView = (function(superClass) {
  1541. extend(ConfigView, superClass);
  1542. function ConfigView() {
  1543. this.renderValueSelect = bind(this.renderValueSelect, this);
  1544. this.renderValueCheckbox = bind(this.renderValueCheckbox, this);
  1545. this.renderValueTextarea = bind(this.renderValueTextarea, this);
  1546. this.autosizeTextarea = bind(this.autosizeTextarea, this);
  1547. this.renderValueText = bind(this.renderValueText, this);
  1548. this.handleCheckboxChange = bind(this.handleCheckboxChange, this);
  1549. this.handleInputChange = bind(this.handleInputChange, this);
  1550. this.renderSectionItem = bind(this.renderSectionItem, this);
  1551. this.handleResetClick = bind(this.handleResetClick, this);
  1552. this.renderSection = bind(this.renderSection, this);
  1553. this;
  1554. }
  1555. ConfigView.prototype.render = function() {
  1556. return this.config_storage.items.map(this.renderSection);
  1557. };
  1558. ConfigView.prototype.renderSection = function(section) {
  1559. return h("div.section", {
  1560. key: section.title
  1561. }, [h("h2", section.title), h("div.config-items", section.items.map(this.renderSectionItem))]);
  1562. };
  1563. ConfigView.prototype.handleResetClick = function(e) {
  1564. var config_key, default_value, node, ref;
  1565. node = e.currentTarget;
  1566. config_key = node.attributes.config_key.value;
  1567. default_value = (ref = node.attributes.default_value) != null ? ref.value : void 0;
  1568. return Page.cmd("wrapperConfirm", ["Reset " + config_key + " value?", "Reset to default"], (function(_this) {
  1569. return function(res) {
  1570. if (res) {
  1571. _this.values[config_key] = default_value;
  1572. }
  1573. return Page.projector.scheduleRender();
  1574. };
  1575. })(this));
  1576. };
  1577. ConfigView.prototype.renderSectionItem = function(item) {
  1578. var marker_title, ref, value_changed, value_default, value_pos;
  1579. value_pos = item.value_pos;
  1580. if (item.type === "textarea") {
  1581. if (value_pos == null) {
  1582. value_pos = "fullwidth";
  1583. }
  1584. } else {
  1585. if (value_pos == null) {
  1586. value_pos = "right";
  1587. }
  1588. }
  1589. value_changed = this.config_storage.formatValue(this.values[item.key]) !== item.value;
  1590. value_default = this.config_storage.formatValue(this.values[item.key]) === item["default"];
  1591. if ((ref = item.key) === "open_browser" || ref === "fileserver_port") {
  1592. value_default = true;
  1593. }
  1594. marker_title = "Changed from default value: " + item["default"] + " -> " + this.values[item.key];
  1595. if (item.pending) {
  1596. marker_title += " (change pending until client restart)";
  1597. }
  1598. if (typeof item.isHidden === "function" ? item.isHidden() : void 0) {
  1599. return null;
  1600. }
  1601. return h("div.config-item", {
  1602. key: item.title,
  1603. enterAnimation: Animation.slideDown,
  1604. exitAnimation: Animation.slideUpInout
  1605. }, [
  1606. h("div.title", [h("h3", item.title), h("div.description", item.description)]), h("div.value.value-" + value_pos, item.type === "select" ? this.renderValueSelect(item) : item.type === "checkbox" ? this.renderValueCheckbox(item) : item.type === "textarea" ? this.renderValueTextarea(item) : this.renderValueText(item), h("a.marker", {
  1607. href: "#Reset",
  1608. title: marker_title,
  1609. onclick: this.handleResetClick,
  1610. config_key: item.key,
  1611. default_value: item["default"],
  1612. classes: {
  1613. "default": value_default,
  1614. changed: value_changed,
  1615. visible: !value_default || value_changed || item.pending,
  1616. pending: item.pending
  1617. }
  1618. }, "\u2022"))
  1619. ]);
  1620. };
  1621. ConfigView.prototype.handleInputChange = function(e) {
  1622. var config_key, node;
  1623. node = e.target;
  1624. config_key = node.attributes.config_key.value;
  1625. this.values[config_key] = node.value;
  1626. return Page.projector.scheduleRender();
  1627. };
  1628. ConfigView.prototype.handleCheckboxChange = function(e) {
  1629. var config_key, node, value;
  1630. node = e.currentTarget;
  1631. config_key = node.attributes.config_key.value;
  1632. value = !node.classList.contains("checked");
  1633. this.values[config_key] = value;
  1634. return Page.projector.scheduleRender();
  1635. };
  1636. ConfigView.prototype.renderValueText = function(item) {
  1637. var value;
  1638. value = this.values[item.key];
  1639. if (!value) {
  1640. value = "";
  1641. }
  1642. return h("input.input-" + item.type, {
  1643. type: item.type,
  1644. config_key: item.key,
  1645. value: value,
  1646. placeholder: item.placeholder,
  1647. oninput: this.handleInputChange
  1648. });
  1649. };
  1650. ConfigView.prototype.autosizeTextarea = function(e) {
  1651. var h, height_before, node, scrollh;
  1652. if (e.currentTarget) {
  1653. node = e.currentTarget;
  1654. } else {
  1655. node = e;
  1656. }
  1657. height_before = node.style.height;
  1658. if (height_before) {
  1659. node.style.height = "0px";
  1660. }
  1661. h = node.offsetHeight;
  1662. scrollh = node.scrollHeight + 20;
  1663. if (scrollh > h) {
  1664. return node.style.height = scrollh + "px";
  1665. } else {
  1666. return node.style.height = height_before;
  1667. }
  1668. };
  1669. ConfigView.prototype.renderValueTextarea = function(item) {
  1670. var value;
  1671. value = this.values[item.key];
  1672. if (!value) {
  1673. value = "";
  1674. }
  1675. return h("textarea.input-" + item.type + ".input-text", {
  1676. type: item.type,
  1677. config_key: item.key,
  1678. oninput: this.handleInputChange,
  1679. afterCreate: this.autosizeTextarea,
  1680. updateAnimation: this.autosizeTextarea,
  1681. value: value,
  1682. placeholder: item.placeholder
  1683. });
  1684. };
  1685. ConfigView.prototype.renderValueCheckbox = function(item) {
  1686. var checked;
  1687. if (this.values[item.key] && this.values[item.key] !== "False") {
  1688. checked = true;
  1689. } else {
  1690. checked = false;
  1691. }
  1692. return h("div.checkbox", {
  1693. onclick: this.handleCheckboxChange,
  1694. config_key: item.key,
  1695. classes: {
  1696. checked: checked
  1697. }
  1698. }, h("div.checkbox-skin"));
  1699. };
  1700. ConfigView.prototype.renderValueSelect = function(item) {
  1701. return h("select.input-select", {
  1702. config_key: item.key,
  1703. oninput: this.handleInputChange
  1704. }, item.options.map((function(_this) {
  1705. return function(option) {
  1706. return h("option", {
  1707. selected: option.value.toString() === _this.values[item.key],
  1708. value: option.value
  1709. }, option.title);
  1710. };
  1711. })(this)));
  1712. };
  1713. return ConfigView;
  1714. })(Class);
  1715. window.ConfigView = ConfigView;
  1716. }).call(this);
  1717. /* ---- UiConfig.coffee ---- */
  1718. (function() {
  1719. var UiConfig,
  1720. bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
  1721. extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  1722. hasProp = {}.hasOwnProperty;
  1723. window.h = maquette.h;
  1724. UiConfig = (function(superClass) {
  1725. extend(UiConfig, superClass);
  1726. function UiConfig() {
  1727. this.renderBottomRestart = bind(this.renderBottomRestart, this);
  1728. this.handleRestartClick = bind(this.handleRestartClick, this);
  1729. this.renderBottomSave = bind(this.renderBottomSave, this);
  1730. this.handleSaveClick = bind(this.handleSaveClick, this);
  1731. this.render = bind(this.render, this);
  1732. this.saveValue = bind(this.saveValue, this);
  1733. this.saveValues = bind(this.saveValues, this);
  1734. this.getValuesPending = bind(this.getValuesPending, this);
  1735. this.getValuesChanged = bind(this.getValuesChanged, this);
  1736. this.createProjector = bind(this.createProjector, this);
  1737. this.updateConfig = bind(this.updateConfig, this);
  1738. this.onOpenWebsocket = bind(this.onOpenWebsocket, this);
  1739. return UiConfig.__super__.constructor.apply(this, arguments);
  1740. }
  1741. UiConfig.prototype.init = function() {
  1742. this.save_visible = true;
  1743. this.config = null;
  1744. this.values = null;
  1745. this.config_view = new ConfigView();
  1746. return window.onbeforeunload = (function(_this) {
  1747. return function() {
  1748. if (_this.getValuesChanged().length > 0) {
  1749. return true;
  1750. } else {
  1751. return null;
  1752. }
  1753. };
  1754. })(this);
  1755. };
  1756. UiConfig.prototype.onOpenWebsocket = function() {
  1757. this.cmd("wrapperSetTitle", "Config - ZeroNet");
  1758. this.cmd("serverInfo", {}, (function(_this) {
  1759. return function(server_info) {
  1760. return _this.server_info = server_info;
  1761. };
  1762. })(this));
  1763. this.restart_loading = false;
  1764. return this.updateConfig();
  1765. };
  1766. UiConfig.prototype.updateConfig = function(cb) {
  1767. return this.cmd("configList", [], (function(_this) {
  1768. return function(res) {
  1769. var item, key, value;
  1770. _this.config = res;
  1771. _this.values = {};
  1772. _this.config_storage = new ConfigStorage(_this.config);
  1773. _this.config_view.values = _this.values;
  1774. _this.config_view.config_storage = _this.config_storage;
  1775. for (key in res) {
  1776. item = res[key];
  1777. value = item.value;
  1778. _this.values[key] = _this.config_storage.formatValue(value);
  1779. }
  1780. _this.projector.scheduleRender();
  1781. return typeof cb === "function" ? cb() : void 0;
  1782. };
  1783. })(this));
  1784. };
  1785. UiConfig.prototype.createProjector = function() {
  1786. this.projector = maquette.createProjector();
  1787. this.projector.replace($("#content"), this.render);
  1788. this.projector.replace($("#bottom-save"), this.renderBottomSave);
  1789. return this.projector.replace($("#bottom-restart"), this.renderBottomRestart);
  1790. };
  1791. UiConfig.prototype.getValuesChanged = function() {
  1792. var key, ref, ref1, value, values_changed;
  1793. values_changed = [];
  1794. ref = this.values;
  1795. for (key in ref) {
  1796. value = ref[key];
  1797. if (this.config_storage.formatValue(value) !== this.config_storage.formatValue((ref1 = this.config[key]) != null ? ref1.value : void 0)) {
  1798. values_changed.push({
  1799. key: key,
  1800. value: value
  1801. });
  1802. }
  1803. }
  1804. return values_changed;
  1805. };
  1806. UiConfig.prototype.getValuesPending = function() {
  1807. var item, key, ref, values_pending;
  1808. values_pending = [];
  1809. ref = this.config;
  1810. for (key in ref) {
  1811. item = ref[key];
  1812. if (item.pending) {
  1813. values_pending.push(key);
  1814. }
  1815. }
  1816. return values_pending;
  1817. };
  1818. UiConfig.prototype.saveValues = function(cb) {
  1819. var base, changed_values, default_value, i, item, j, last, len, match, message, results, value, value_same_as_default;
  1820. changed_values = this.getValuesChanged();
  1821. results = [];
  1822. for (i = j = 0, len = changed_values.length; j < len; i = ++j) {
  1823. item = changed_values[i];
  1824. last = i === changed_values.length - 1;
  1825. value = this.config_storage.deformatValue(item.value, typeof this.config[item.key]["default"]);
  1826. default_value = this.config_storage.deformatValue(this.config[item.key]["default"], typeof this.config[item.key]["default"]);
  1827. value_same_as_default = JSON.stringify(default_value) === JSON.stringify(value);
  1828. if (this.config[item.key].item.valid_pattern && !(typeof (base = this.config[item.key].item).isHidden === "function" ? base.isHidden() : void 0)) {
  1829. match = value.match(this.config[item.key].item.valid_pattern);
  1830. if (!match || match[0] !== value) {
  1831. message = "Invalid value of " + this.config[item.key].item.title + ": " + value + " (does not matches " + this.config[item.key].item.valid_pattern + ")";
  1832. Page.cmd("wrapperNotification", ["error", message]);
  1833. cb(false);
  1834. break;
  1835. }
  1836. }
  1837. if (value_same_as_default) {
  1838. value = null;
  1839. }
  1840. results.push(this.saveValue(item.key, value, last ? cb : null));
  1841. }
  1842. return results;
  1843. };
  1844. UiConfig.prototype.saveValue = function(key, value, cb) {
  1845. if (key === "open_browser") {
  1846. if (value) {
  1847. value = "default_browser";
  1848. } else {
  1849. value = "False";
  1850. }
  1851. }
  1852. return Page.cmd("configSet", [key, value], (function(_this) {
  1853. return function(res) {
  1854. if (res !== "ok") {
  1855. Page.cmd("wrapperNotification", ["error", res.error]);
  1856. }
  1857. return typeof cb === "function" ? cb(true) : void 0;
  1858. };
  1859. })(this));
  1860. };
  1861. UiConfig.prototype.render = function() {
  1862. if (!this.config) {
  1863. return h("div.content");
  1864. }
  1865. return h("div.content", [this.config_view.render()]);
  1866. };
  1867. UiConfig.prototype.handleSaveClick = function() {
  1868. this.save_loading = true;
  1869. this.logStart("Save");
  1870. this.saveValues((function(_this) {
  1871. return function(success) {
  1872. _this.save_loading = false;
  1873. _this.logEnd("Save");
  1874. if (success) {
  1875. _this.updateConfig();
  1876. }
  1877. return Page.projector.scheduleRender();
  1878. };
  1879. })(this));
  1880. return false;
  1881. };
  1882. UiConfig.prototype.renderBottomSave = function() {
  1883. var values_changed;
  1884. values_changed = this.getValuesChanged();
  1885. return h("div.bottom.bottom-save", {
  1886. classes: {
  1887. visible: values_changed.length
  1888. }
  1889. }, h("div.bottom-content", [
  1890. h("div.title", values_changed.length + " configuration item value changed"), h("a.button.button-submit.button-save", {
  1891. href: "#Save",
  1892. classes: {
  1893. loading: this.save_loading
  1894. },
  1895. onclick: this.handleSaveClick
  1896. }, "Save settings")
  1897. ]));
  1898. };
  1899. UiConfig.prototype.handleRestartClick = function() {
  1900. this.restart_loading = true;
  1901. Page.cmd("serverShutdown", {
  1902. restart: true
  1903. });
  1904. Page.projector.scheduleRender();
  1905. return false;
  1906. };
  1907. UiConfig.prototype.renderBottomRestart = function() {
  1908. var values_changed, values_pending;
  1909. values_pending = this.getValuesPending();
  1910. values_changed = this.getValuesChanged();
  1911. return h("div.bottom.bottom-restart", {
  1912. classes: {
  1913. visible: values_pending.length && !values_changed.length
  1914. }
  1915. }, h("div.bottom-content", [
  1916. h("div.title", "Some changed settings requires restart"), h("a.button.button-submit.button-restart", {
  1917. href: "#Restart",
  1918. classes: {
  1919. loading: this.restart_loading
  1920. },
  1921. onclick: this.handleRestartClick
  1922. }, "Restart ZeroNet client")
  1923. ]));
  1924. };
  1925. return UiConfig;
  1926. })(ZeroFrame);
  1927. window.Page = new UiConfig();
  1928. window.Page.createProjector();
  1929. }).call(this);