create_table_manually.mako 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. ## Licensed to Cloudera, Inc. under one
  2. ## or more contributor license agreements. See the NOTICE file
  3. ## distributed with this work for additional information
  4. ## regarding copyright ownership. Cloudera, Inc. licenses this file
  5. ## to you under the Apache License, Version 2.0 (the
  6. ## "License"); you may not use this file except in compliance
  7. ## with the License. You may obtain a copy of the License at
  8. ##
  9. ## http://www.apache.org/licenses/LICENSE-2.0
  10. ##
  11. ## Unless required by applicable law or agreed to in writing, software
  12. ## distributed under the License is distributed on an "AS IS" BASIS,
  13. ## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ## See the License for the specific language governing permissions and
  15. ## limitations under the License.
  16. <%!
  17. from desktop.views import commonheader, commonfooter
  18. from django.utils.translation import ugettext as _
  19. %>
  20. <%namespace name="comps" file="beeswax_components.mako" />
  21. <%namespace name="layout" file="layout.mako" />
  22. ${ commonheader(_("Create table manually"), 'metastore', user) | n,unicode }
  23. ${ layout.metastore_menubar() }
  24. <div class="container-fluid">
  25. <div class="row-fluid">
  26. <div class="span3">
  27. <div class="sidebar-nav">
  28. <ul class="nav nav-list">
  29. <li class="nav-header">${_('Actions')}</li>
  30. <li><a href="${ url(app_name + ':import_wizard', database=database)}"><i class="fa fa-files-o"></i> ${_('Create a new table from a file')}</a></li>
  31. <li><a href="${ url(app_name + ':create_table', database=database)}"><i class="fa fa-wrench"></i> ${_('Create a new table manually')}</a></li>
  32. </ul>
  33. </div>
  34. </div>
  35. <div class="span9">
  36. <div class="card" style="margin-top: 0">
  37. <h1 class="card-heading simple">${_('Create a new table manually')}</h1>
  38. <div class="card-body">
  39. <p>
  40. <ul class="nav nav-pills">
  41. <li class="active"><a href="#step1" class="step">${_('Step 1: Name')}</a></li>
  42. <li><a href="#step2" class="step">${_('Step 2: Record Format')}</a></li>
  43. <li><a href="#step3" class="step">${_('Step 3: Serialization')}</a></li>
  44. <li><a href="#step4" class="step">${_('Step 4: File Format')}</a></li>
  45. <li><a href="#step5" class="step">${_('Step 5: Location')}</a></li>
  46. <li><a href="#step6" class="step">${_('Step 6: Columns')}</a></li>
  47. </ul>
  48. <form action="#" method="POST" id="mainForm" class="form-horizontal">
  49. <div class="steps">
  50. <div id="step1" class="stepDetails">
  51. <fieldset>
  52. <div class="alert alert-info"><h3>${_('Create a table')}</h3>${_("Let's start with a name and description for where we'll store your data.")}</div>
  53. <div class="control-group">
  54. ${comps.bootstrapLabel(table_form["name"])}
  55. <div class="controls">
  56. ${comps.field(table_form["name"], attrs=dict(
  57. placeholder=_('table_name'),
  58. )
  59. )}
  60. <span class="help-inline error-inline hide">${_('This field is required. Spaces are not allowed.')}</span>
  61. <p class="help-block">
  62. ${_('Name of the new table. Table names must be globally unique. Table names tend to correspond to the directory where the data will be stored.')}
  63. </p>
  64. </div>
  65. </div>
  66. <div class="control-group">
  67. ${comps.bootstrapLabel(table_form["comment"])}
  68. <div class="controls">
  69. ${comps.field(table_form["comment"], attrs=dict(
  70. placeholder=_('Optional'),
  71. )
  72. )}
  73. <p class="help-block">
  74. ${_("Use a table comment to describe your table. For example, note the data's provenance and any caveats users need to know.")}
  75. </p>
  76. </div>
  77. </div>
  78. </fieldset>
  79. </div>
  80. <div id="step2" class="stepDetails hide">
  81. <fieldset>
  82. <div class="alert alert-info"><h3>${_('Choose Your Record Format')}</h3>
  83. ${_("Individual records are broken up into columns either with delimiters (e.g., CSV or TSV) or using a specific serialization/deserialization (SerDe) implementation. (One common specialized SerDe is for parsing out columns with a regular expression.)")}
  84. </div>
  85. <%
  86. selected = table_form["row_format"].data or table_form["row_format"].field.initial
  87. %>
  88. <div class="control-group">
  89. <label class="control-label" id="formatRadio">${_('Record format')}</label>
  90. <div class="controls">
  91. <label class="radio">
  92. <input type="radio" name="table-row_format" value="Delimited"
  93. % if selected == "Delimited":
  94. checked
  95. % endif
  96. >
  97. ${_('Delimited')}
  98. <span class="help-inline">
  99. ${_('(Data files use delimiters, like commas (CSV) or tabs.)')}
  100. </span>
  101. </label>
  102. <label class="radio">
  103. <input type="radio" name="table-row_format" value="SerDe"
  104. % if selected == "SerDe":
  105. checked
  106. % endif
  107. >
  108. ${_('SerDe')}
  109. <span class="help-inline">
  110. ${_('(Enter a specialized serialization implementation.)')}
  111. </span>
  112. </label>
  113. </div>
  114. </div>
  115. </fieldset>
  116. </div>
  117. <div id="step3" class="stepDetails hide">
  118. <fieldset>
  119. <div id="step3Delimited" class="stepDetailsInner">
  120. <div class="alert alert-info"><h3>${_('Configure Record Serialization')}</h3>
  121. ${_('Only supports single-character delimiters.')}
  122. </div>
  123. <div class="control-group">
  124. ${comps.bootstrapLabel(table_form["field_terminator"])}
  125. <div class="controls">
  126. ${comps.field(table_form["field_terminator"], render_default=True)}
  127. <span class="help-inline error-inline hide">${_('This field is required. Spaces are not allowed. Terminator must be exactly one character.')}</span>
  128. <span class="help-block">
  129. ${_('Enter the column delimiter. Must be a single character. Use syntax like "\\001" or "\\t" for special characters.')}
  130. </span>
  131. </div>
  132. </div>
  133. <div class="control-group">
  134. ${comps.bootstrapLabel(table_form["collection_terminator"])}
  135. <div class="controls">
  136. ${comps.field(table_form["collection_terminator"], render_default=True)}
  137. <span class="help-inline error-inline hide">${_('This field is required. Spaces are not allowed. Terminator must be exactly one character.')}</span>
  138. <span class="help-block">
  139. ${_('Use for array types.')}
  140. </span>
  141. </div>
  142. </div>
  143. <div class="control-group">
  144. ${comps.bootstrapLabel(table_form["map_key_terminator"])}
  145. <div class="controls">
  146. ${comps.field(table_form["map_key_terminator"], render_default=True)}
  147. <span class="help-inline error-inline hide">${_('This field is required. Spaces are not allowed. Terminator must be exactly one character.')}</span>
  148. <span class="help-block">
  149. ${_('Use for map types.')}
  150. </span>
  151. </div>
  152. </div>
  153. </div>
  154. <div id="step3SerDe" class="hide stepDetailsInner">
  155. <div class="alert alert-info"><h3>${_('Configure Record Serialization')}</h3>
  156. </div>
  157. <div class="control-group">
  158. ${comps.bootstrapLabel(table_form["serde_name"])}
  159. <div class="controls">
  160. ${comps.field(table_form["serde_name"], attrs=dict(
  161. placeholder='com.acme.hive.SerDe',
  162. )
  163. )}
  164. <span class="help-block">
  165. ${_('The Java class name of your SerDe.')} <em>${_('e.g.')}</em>, org.apache.hadoop.hive.contrib.serde2.RegexSerDe
  166. </span>
  167. </div>
  168. </div>
  169. <div class="control-group">
  170. ${comps.bootstrapLabel(table_form["serde_properties"])}
  171. <div class="controls">
  172. ${comps.field(table_form["serde_properties"], attrs=dict(
  173. placeholder='"prop" = "value", "prop2" = "value2"',
  174. )
  175. )}
  176. <span class="help-block">
  177. ${_('Properties to pass to the (de)serialization mechanism.')} <em>${_('e.g.')},</em>, "input.regex" = "([^ ]*) ([^ ]*) ([^ ]*) (-|\\[[^\\]]*\\]) ([^ \"]*|\"[^\"]*\") (-|[0-9]*) (-|[0-9]*)(?: ([^ \"]*|\"[^\"]*\") ([^ \"]*|\"[^\"]*\"))?", "output.format.string" = "%1$s %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s"
  178. </span>
  179. </div>
  180. </div>
  181. </div>
  182. </fieldset>
  183. </div>
  184. <div id="step4" class="stepDetails hide">
  185. <fieldset>
  186. <div class="alert alert-info"><h3>${_('Choose a File Format')}</h3>
  187. ${_('Use')} <strong>TextFile</strong> ${_('for newline-delimited text files.')}
  188. ${_('Use')} <strong>SequenceFile</strong> ${_("for Hadoop's binary serialization format.")}
  189. ${_('Use')} <strong>InputFormat</strong> ${_('to choose a custom implementation.')}
  190. <br/>
  191. </div>
  192. <div class="control-group">
  193. <label id="fileFormatRadio" class="control-label">${_('File format')}</label>
  194. <div class="controls">
  195. ${comps.field(table_form["file_format"],
  196. render_default=True,
  197. klass="bw-file_formats",
  198. notitle=True
  199. )}
  200. </div>
  201. </div>
  202. <div id="inputFormatDetails" class="hide">
  203. <div class="control-group">
  204. ${comps.bootstrapLabel(table_form["input_format_class"])}
  205. <div class="controls">
  206. ${comps.field(table_form["input_format_class"], attrs=dict(
  207. placeholder='com.acme.data.MyInputFormat',
  208. )
  209. )}
  210. <span class="help-inline error-inline hide">${_('This field is required. Spaces are not allowed.')}</span>
  211. <span class="help-block">
  212. ${_('Java class used to read data.')}
  213. </span>
  214. </div>
  215. </div>
  216. <div class="control-group">
  217. ${comps.bootstrapLabel(table_form["output_format_class"])}
  218. <div class="controls">
  219. ${comps.field(table_form["output_format_class"], attrs=dict(
  220. placeholder='com.acme.data.MyOutputFormat',
  221. )
  222. )}
  223. <span class="help-inline error-inline hide">${_('This field is required. Spaces are not allowed.')}</span>
  224. <span class="help-block">
  225. ${_('Java class used to write data.')}
  226. </span>
  227. </div>
  228. </div>
  229. </div>
  230. </fieldset>
  231. </div>
  232. <div id="step5" class="stepDetails hide">
  233. <fieldset>
  234. <div class="alert alert-info"><h3>${_("Choose Where Your Table's Data is Stored")}</h3>
  235. </div>
  236. <div class="control-group">
  237. <label class="control-label">${_('Location')}</label>
  238. <div class="controls">
  239. <label class="checkbox">
  240. ${comps.field(table_form["use_default_location"],
  241. render_default=True
  242. )}
  243. ${_('Use default location')}
  244. </label>
  245. <span class="help-block">
  246. ${_('Store your table in the default location (controlled by Hive, and typically')} <em>/user/hive/warehouse/table_name</em>).
  247. </span>
  248. </div>
  249. </div>
  250. <div id="location" class="control-group hide">
  251. ${comps.bootstrapLabel(table_form["external_location"])}
  252. <div class="controls">
  253. ${comps.field(table_form["external_location"],
  254. placeholder="/user/user_name/data_dir",
  255. klass="pathChooser input-xxlarge",
  256. file_chooser=True,
  257. show_errors=False
  258. )}
  259. <span class="help-block">
  260. ${_("Enter the path (on HDFS) to your table's data location")}
  261. </span>
  262. </div>
  263. </div>
  264. </fieldset>
  265. </div>
  266. <div id="step6" class="stepDetails hide">
  267. <fieldset>
  268. <div class="alert alert-info"><h3>${_('Configure Table Columns')}</h3>
  269. </div>
  270. % for form in columns_form.forms:
  271. ${render_column(form)}
  272. %endfor
  273. <div class="hide">
  274. ${unicode(columns_form.management_form) | n}
  275. </div>
  276. <button class="btn addColumnBtn" value="True" name="columns-add" type="submit">${_('Add a column')}</button>
  277. </fieldset>
  278. <br/><br/>
  279. <fieldset>
  280. <div class="alert alert-info"><h3>${_('Configure Partitions')}</h3>
  281. ${_('If your data is naturally partitioned (by date, for example), partitions are a way to tell the query server that data for a specific partition value are stored together.')}
  282. ${_('The query server establishes a mapping between directories on disk')}
  283. (<em>${_('e.g.')},</em> <code>/user/hive/warehouse/logs/dt=20100101/</code>)
  284. ${_('and the data for that day. Partitions are virtual columns; they are not represented in the data itself, but are determined by the data location. The query server implements query optimizations such that queries that are specific to a single partition need not read the data in other partitions.')}
  285. </div>
  286. % for form in partitions_form.forms:
  287. ${render_column(form, True)}
  288. % endfor
  289. <div class="hide">
  290. ${unicode(partitions_form.management_form) | n}
  291. </div>
  292. <button class="btn addPartitionBtn" value="True" name="partitions-add" type="submit">${_('Add a partition')}</button>
  293. </fieldset>
  294. </div>
  295. </div>
  296. <div class="form-actions" style="padding-left: 10px">
  297. <button type="button" id="backBtn" class="btn hide">${_('Back')}</button>
  298. <button type="button" id="nextBtn" class="btn btn-primary">${_('Next')}</button>
  299. <input id="submit" type="submit" name="create" class="btn btn-primary hide" value="${_('Create table')}" />
  300. </div>
  301. </form>
  302. </p>
  303. </div>
  304. </div>
  305. </div>
  306. </div>
  307. </div>
  308. <%def name="render_column(form, is_partition_form=False)">
  309. <div class="cnt well">
  310. <div class="remove">
  311. ${comps.field(form['_deleted'], tag="button", button_text="x", notitle=True, attrs=dict(
  312. type="submit",
  313. title=_("Delete this column"),
  314. klass="btn btn-mini removeBtn"
  315. ), value=True)}
  316. </div>
  317. <div class="control-group">
  318. <label class="control-label">${_('Column name')}</label>
  319. <div class="controls">
  320. <input class="column" name="${form["column_name"].html_name | n}" value="${form["column_name"].data or ''}" placeholder="${_('Column Name')}"/>
  321. <span class="help-inline error-inline hide">${_('This field is required. Spaces are not allowed.')}</span>
  322. <span class="help-inline error-inline error-inline-bis hide">${_('There is another field with the same name.')}</span>
  323. <span class="help-block">
  324. ${_('Column name must be single words that start with a letter or a digit.')}
  325. </span>
  326. </div>
  327. </div>
  328. <div class="control-group">
  329. <label class="control-label">${_('Column type')}</label>
  330. <div class="controls columnType">
  331. ${comps.field(form["column_type"],
  332. render_default=True
  333. )}
  334. <span class="help-block">
  335. ${_('Type for this column. Certain advanced types (namely, structs) are not exposed in this interface.')}
  336. </span>
  337. </div>
  338. </div>
  339. % if is_partition_form == False:
  340. <div class="arraySpec hide">
  341. <div class="control-group">
  342. <label class="control-label">${_('Array value type')}</label>
  343. <div class="controls">
  344. ${comps.field(form["array_type"], render_default=True)}
  345. <span class="help-block">
  346. ${_('Type of the array values.')}
  347. </span>
  348. </div>
  349. </div>
  350. </div>
  351. <div class="mapSpec hide">
  352. <div class="control-group">
  353. <label class="control-label">${_('Map Key type')}</label>
  354. <div class="controls">
  355. ${comps.field(form["map_key_type"], render_default=True)}
  356. <span class="help-inline">
  357. ${_('Type of the map keys.')}
  358. </span>
  359. </div>
  360. </div>
  361. <div class="control-group">
  362. <label class="control-label">${_('Map Value type')}</label>
  363. <div class="controls">
  364. ${comps.field(form["map_value_type"], render_default=True)}
  365. <span class="help-inline">
  366. ${_('Type of the map values.')}
  367. </span>
  368. </div>
  369. </div>
  370. </div>
  371. % endif
  372. ${unicode(form["_exists"]) | n}
  373. </div>
  374. </%def>
  375. <div id="chooseFile" class="modal hide fade">
  376. <div class="modal-header">
  377. <a href="#" class="close" data-dismiss="modal">&times;</a>
  378. <h3>${_('Choose a file')}</h3>
  379. </div>
  380. <div class="modal-body">
  381. <div id="filechooser">
  382. </div>
  383. </div>
  384. <div class="modal-footer">
  385. </div>
  386. </div>
  387. <style type="text/css">
  388. #filechooser {
  389. min-height: 100px;
  390. overflow-y: auto;
  391. margin-top: 10px;
  392. height: 250px;
  393. }
  394. .inputs-list {
  395. list-style: none outside none;
  396. margin-left: 0;
  397. }
  398. .remove {
  399. float: right;
  400. }
  401. .error-inline {
  402. color: #B94A48;
  403. font-weight: bold;
  404. }
  405. .steps {
  406. min-height: 350px;
  407. margin-top: 10px;
  408. }
  409. div .alert {
  410. margin-bottom: 30px;
  411. }
  412. </style>
  413. </div>
  414. <script type="text/javascript" charset="utf-8">
  415. $(document).ready(function () {
  416. if ($(".removeBtn").length == 1) {
  417. $(".removeBtn").first().hide();
  418. }
  419. $(".fileChooserBtn").click(function (e) {
  420. e.preventDefault();
  421. var _destination = $(this).attr("data-filechooser-destination");
  422. $("#filechooser").jHueFileChooser({
  423. initialPath: $("input[name='" + _destination + "']").val(),
  424. onFolderChoose: function (filePath) {
  425. $("input[name='" + _destination + "']").val(filePath);
  426. $("#chooseFile").modal("hide");
  427. },
  428. createFolder: false,
  429. selectFolder: true,
  430. uploadFile: false
  431. });
  432. $("#chooseFile").modal("show");
  433. });
  434. $(".step").click(function (event) {
  435. event.preventDefault();
  436. if (validateForm()) {
  437. $(".stepDetails").hide();
  438. var _step = $(this).attr("href");
  439. $(_step).css("visibility", "visible").show();
  440. $("#backBtn").hide();
  441. if (_step != "#step1") {
  442. $("#backBtn").css("visibility", "visible").show();
  443. }
  444. if (_step != "#step6") {
  445. $("#nextBtn").show();
  446. $("#submit").hide();
  447. }
  448. else {
  449. $("#nextBtn").hide();
  450. $("#submit").css("visibility", "visible").show();
  451. }
  452. $(".step").parent().removeClass("active");
  453. $(this).parent().addClass("active");
  454. }
  455. });
  456. $("#nextBtn").click(function () {
  457. $("ul.nav-pills li.active").next().find("a").click();
  458. });
  459. $("#backBtn").click(function () {
  460. $("ul.nav-pills li.active").prev().find("a").click();
  461. });
  462. $("#submit").click(function (event) {
  463. // validate step 6
  464. if (! validateStep6()) {
  465. event.preventDefault();
  466. }
  467. });
  468. var _url = location.href;
  469. if (_url.indexOf("#") > -1) {
  470. $(".step[href='" + _url.substring(_url.indexOf("#"), _url.length) + "']").click();
  471. }
  472. $("#id_table-field_terminator_1").css("margin-left", "4px").attr("placeholder", "${_('Type your field terminator here')}").hide();
  473. $("#id_table-field_terminator_0").change(function () {
  474. if ($(this).val() == "__other__") {
  475. $("#id_table-field_terminator_1").show();
  476. }
  477. else {
  478. $("#id_table-field_terminator_1").hide().nextAll(".error-inline").addClass("hide");
  479. }
  480. });
  481. $("#id_table-collection_terminator_1").css("margin-left", "4px").attr("placeholder", "${_('Type your collection terminator here')}").hide();
  482. $("#id_table-collection_terminator_0").change(function () {
  483. if ($(this).val() == "__other__") {
  484. $("#id_table-collection_terminator_1").show();
  485. }
  486. else {
  487. $("#id_table-collection_terminator_1").hide().nextAll(".error-inline").addClass("hide");
  488. }
  489. });
  490. $("#id_table-map_key_terminator_1").css("margin-left", "4px").attr("placeholder", "${_('Type your map key terminator here')}").hide();
  491. $("#id_table-map_key_terminator_0").change(function () {
  492. if ($(this).val() == "__other__") {
  493. $("#id_table-map_key_terminator_1").show();
  494. }
  495. else {
  496. $("#id_table-map_key_terminator_1").hide().nextAll(".error-inline").addClass("hide");
  497. }
  498. });
  499. // fire the event on page load
  500. $("#id_table-field_terminator_0").change();
  501. $("#id_table-collection_terminator_0").change();
  502. $("#id_table-map_key_terminator_0").change();
  503. // show the first validation error if any
  504. if ($(".errorlist").length > 0) {
  505. $(".step[href='#" + $(".errorlist").eq(0).closest(".stepDetails").attr("id") + "']").click();
  506. }
  507. $("input[name='table-row_format']").change(function () {
  508. $(".stepDetailsInner").hide();
  509. $("#step3" + $(this).val()).show();
  510. });
  511. $("input[name='table-file_format']").change(function () {
  512. $("#inputFormatDetails").hide();
  513. if ($(this).val() == "InputFormat") {
  514. $("#inputFormatDetails").slideDown();
  515. }
  516. });
  517. $("#id_table-use_default_location").change(function () {
  518. if (!$(this).is(":checked")) {
  519. $("#location").slideDown();
  520. }
  521. else {
  522. $("#location").slideUp();
  523. }
  524. });
  525. $("#step6").find("button").click(function () {
  526. $("#mainForm").attr("action", "#step6");
  527. });
  528. $(".columnType").find("select").change(function () {
  529. $(this).parents(".cnt").find(".arraySpec").hide();
  530. $(this).parents(".cnt").find(".mapSpec").hide();
  531. if ($(this).val() == "array") {
  532. $(this).parents(".cnt").find(".arraySpec").show();
  533. }
  534. if ($(this).val() == "map") {
  535. $(this).parents(".cnt").find(".mapSpec").show();
  536. }
  537. });
  538. $("#step4").find("ul").addClass("inputs-list");
  539. $(".addColumnBtn, .addPartitionBtn").click(function (e) {
  540. if (!validateStep6()) {
  541. e.preventDefault();
  542. }
  543. });
  544. function validateStep6() {
  545. var scrollTo = 0;
  546. // step 6
  547. var step6Valid = true;
  548. $(".column").each(function () {
  549. var _field = $(this);
  550. if (!isValid($.trim(_field.val()))) {
  551. showFieldError(_field);
  552. if (scrollTo == 0) {
  553. scrollTo = $(this).position().top - $(this).closest(".well").height();
  554. }
  555. step6Valid = false;
  556. }
  557. else {
  558. hideFieldError(_field);
  559. }
  560. var _lastSecondErrorField = null;
  561. $(".column").not("[name='" + _field.attr("name") + "']").each(function () {
  562. if ($.trim($(this).val()) != "" && $.trim($(this).val()) == $.trim(_field.val())) {
  563. _lastSecondErrorField = $(this);
  564. if (scrollTo == 0) {
  565. scrollTo = _field.position().top - _field.closest(".well").height();
  566. }
  567. step6Valid = false;
  568. }
  569. });
  570. if (_lastSecondErrorField != null) {
  571. showSecondFieldError(_lastSecondErrorField);
  572. }
  573. else {
  574. hideSecondFieldError(_field);
  575. }
  576. });
  577. if (!step6Valid && scrollTo > 0) {
  578. $(window).scrollTop(scrollTo);
  579. }
  580. return step6Valid;
  581. }
  582. function validateForm() {
  583. // step 1
  584. var tableNameFld = $("input[name='table-name']");
  585. if (!isValid($.trim(tableNameFld.val()))) {
  586. showFieldError(tableNameFld);
  587. return false;
  588. }
  589. else {
  590. hideFieldError(tableNameFld);
  591. }
  592. // step 3
  593. var step3Valid = true;
  594. var fieldTerminatorFld = $("#id_table-field_terminator_1");
  595. if ($("#id_table-field_terminator_0").val() == "__other__" && (!isValid($.trim(fieldTerminatorFld.val())) || $.trim(fieldTerminatorFld.val()).length != 1)) {
  596. showFieldError(fieldTerminatorFld);
  597. step3Valid = false;
  598. }
  599. else {
  600. hideFieldError(fieldTerminatorFld);
  601. }
  602. var collectionTerminatorFld = $("#id_table-collection_terminator_1");
  603. if ($("#id_table-collection_terminator_0").val() == "__other__" && (!isValid($.trim(collectionTerminatorFld.val())) || $.trim(collectionTerminatorFld.val()).length != 1)) {
  604. showFieldError(collectionTerminatorFld);
  605. step3Valid = false;
  606. }
  607. else {
  608. hideFieldError(collectionTerminatorFld);
  609. }
  610. var mapKeyTerminatorFld = $("#id_table-map_key_terminator_1");
  611. if ($("#id_table-map_key_terminator_0").val() == "__other__" && (!isValid($.trim(mapKeyTerminatorFld.val())) || $.trim(mapKeyTerminatorFld.val()).length != 1)) {
  612. showFieldError(mapKeyTerminatorFld);
  613. step3Valid = false;
  614. }
  615. else {
  616. hideFieldError(mapKeyTerminatorFld);
  617. }
  618. if (!step3Valid) {
  619. return false;
  620. }
  621. // step 4
  622. var step4Valid = true;
  623. if ($("input[name='table-file_format']:checked").val() == "InputFormat") {
  624. var inputFormatFld = $("input[name='table-input_format_class']");
  625. if (!isValid($.trim(inputFormatFld.val()))) {
  626. showFieldError(inputFormatFld);
  627. step4Valid = false;
  628. }
  629. else {
  630. hideFieldError(inputFormatFld);
  631. }
  632. var outputFormatFld = $("input[name='table-output_format_class']");
  633. if (!isValid($.trim(outputFormatFld.val()))) {
  634. showFieldError(outputFormatFld);
  635. step4Valid = false;
  636. }
  637. else {
  638. hideFieldError(outputFormatFld);
  639. }
  640. }
  641. if (!step4Valid) {
  642. return false;
  643. }
  644. // step 5
  645. var tableExternalLocationFld = $("input[name='table-external_location']");
  646. if (!($("#id_table-use_default_location").is(":checked"))) {
  647. if (!isValid($.trim(tableExternalLocationFld.val()))) {
  648. showFieldError(tableExternalLocationFld);
  649. return false;
  650. }
  651. else {
  652. hideFieldError(tableExternalLocationFld);
  653. }
  654. }
  655. return true;
  656. }
  657. function isValid(str) {
  658. // validates against empty string and no spaces
  659. return (str != "" && str.indexOf(" ") == -1);
  660. }
  661. function showFieldError(field) {
  662. field.nextAll(".error-inline").not(".error-inline-bis").removeClass("hide");
  663. }
  664. function showSecondFieldError(field) {
  665. field.nextAll(".error-inline-bis").removeClass("hide");
  666. }
  667. function hideFieldError(field) {
  668. if (!(field.nextAll(".error-inline").hasClass("hide"))) {
  669. field.nextAll(".error-inline").addClass("hide");
  670. }
  671. }
  672. function hideSecondFieldError(field) {
  673. if (!(field.nextAll(".error-inline-bis").hasClass("hide"))) {
  674. field.nextAll(".error-inline-bis").addClass("hide");
  675. }
  676. }
  677. });
  678. </script>
  679. ${ commonfooter(messages) | n,unicode }