/SPUtility.js

http://sputility.codeplex.com · JavaScript · 1235 lines · 879 code · 167 blank · 189 comment · 146 complexity · b121bff26cb367d30a057136ce4b14cb MD5 · raw file

  1. /*
  2. Name: SPUtility.js
  3. Version: 0.8.1
  4. Description:
  5. A JavaScript library that is used to alter SharePoint's user interface
  6. (mostly NewForm and EditForm). It can be used to populate fields, make
  7. fields read only, or hide a field from view.
  8. Author: Kit Menke
  9. http://SPUtility.codeplex.com/
  10. License: Microsoft Public License (see http://sputility.codeplex.com/license)
  11. Changelog: http://sputility.codeplex.com/wikipage?title=Changelog
  12. */
  13. /*jslint white: true, browser: true, devel: true, onevar: true, undef: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, indent: 3 */
  14. /*global Element: false, Class: false, $: false, $$: false, $A: false, Hash: false, Event: false, Prototype: false, $break: false, $H: false, RTE_GetIFrameContents: false, RTE_TransferTextAreaContentsToIFrame: false, RTE_GetEditorIFrame: false */
  15. // getTextContent credit to Dan Dean
  16. // http://dandean.com/category/code/2009/hatin-on-textcontent-and-innertext/
  17. Element.addMethods({
  18. /**
  19. * Element#getTextContent(@element) -> String
  20. * Cross-browser means of getting Element#textContent or Element#innerText
  21. **/
  22. getTextContent: function (element) {
  23. if (!Object.isUndefined(element.textContent)) {
  24. return element.textContent;
  25. }
  26. return element.innerText;
  27. },
  28. setTextContent: function (element, value) {
  29. if (!Object.isUndefined(element.textContent)) {
  30. element.textContent = value;
  31. }
  32. element.innerText = value;
  33. }
  34. });
  35. //+ Jonas Raoni Soares Silva
  36. //@ http://jsfromhell.com/number/fmt-money [rev. #2]
  37. // Modified to pass JSLint
  38. // c = # of floating point decimal places
  39. // d = decimal separator
  40. // t = thousands separator
  41. Number.prototype.formatMoney = function (c, d, t) {
  42. c = (isNaN(c = Math.abs(c)) ? 2 : c);
  43. d = (d === undefined ? "." : d);
  44. t = (t === undefined ? "," : t);
  45. var n = this,
  46. s = (n < 0 ? "-" : ""),
  47. i = parseInt(n = Math.abs(+n || 0).toFixed(c), 10) + "",
  48. j = (j = i.length) > 3 ? j % 3 : 0;
  49. return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
  50. };
  51. /*
  52. * SPUtility namespace
  53. */
  54. var SPUtility = (function () {
  55. "use strict";
  56. /*
  57. * SPUtility Private Variables
  58. **/
  59. var SPField, SPTextField, SPUserField, SPURLField, SPChoiceField,
  60. SPDateTimeField, SPDateTimeFieldValue, SPFileField, SPCurrencyField,
  61. SPNumberField, SPBooleanField, SPNoteField, SPLookupField, SPLookupMultiField,
  62. _fieldsHashtable = null,
  63. _debugMode = false,
  64. _isSurveyForm = false,
  65. _numErrors = 0;
  66. /*
  67. * SPUtility Private Methods
  68. **/
  69. function log(message, exception) {
  70. var property;
  71. try {
  72. if (!_debugMode) {
  73. return;
  74. }
  75. if (exception) {
  76. message += '\r\n';
  77. for (property in exception) {
  78. if (exception.hasOwnProperty(property)) {
  79. message += property + ': ' + exception[property] + '\r\n';
  80. }
  81. }
  82. }
  83. if (Prototype.Browser.IE || Object.isUndefined(console)) {
  84. _numErrors += 1;
  85. if (_numErrors === 3) {
  86. message = "More than 3 errors (additional errors will not be shown):\r\n" + message;
  87. }
  88. if (_numErrors <= 3) {
  89. alert(message);
  90. }
  91. } else {
  92. console.error(message);
  93. }
  94. } catch (ex) { }
  95. }
  96. function convertStringToNumber(val) {
  97. if (typeof val === "string") {
  98. var match = val.match(/[0-9,.]+/g);
  99. if (null !== match) {
  100. val = match[0].replace(/,/g, ''); // commas to delimit thousands need to be removed
  101. val = parseFloat(val);
  102. }
  103. }
  104. return val;
  105. }
  106. // Gets the input controls for a field (used for Textboxes)
  107. function getInputControl(spField) {
  108. var controls = spField.Controls.select('input');
  109. if (null !== controls && 1 === controls.length) {
  110. return controls[0];
  111. }
  112. throw 'Unable to retrieve the input control for ' + spField.Name;
  113. }
  114. function getHashFromInputControls(spField, selector) {
  115. var oHash = null, inputTags = spField.Controls.select(selector), inputLabel, key;
  116. if (null !== inputTags && inputTags.length > 0) {
  117. oHash = new Hash();
  118. inputTags.each(function (elem) {
  119. inputLabel = elem.next(0);
  120. if (!Object.isUndefined(inputLabel)) {
  121. key = inputLabel.getTextContent();
  122. oHash.set(key, elem);
  123. }
  124. });
  125. }
  126. return oHash;
  127. }
  128. function getSPFieldType(element) {
  129. var matches, comment, n;
  130. try {
  131. // find the HTML comment and get the field's type
  132. for (n = 0; n < element.childNodes.length; n += 1) {
  133. if (8 === element.childNodes[n].nodeType) {
  134. comment = element.childNodes[n].data;
  135. matches = comment.match(/SPField\w+/);
  136. if (null !== matches) {
  137. return matches[0];
  138. }
  139. break;
  140. }
  141. }
  142. } catch (ex) {
  143. log('getSPFieldType: Error getting field type', ex);
  144. }
  145. return null;
  146. }
  147. function getSPFieldFromType(spFieldParams) {
  148. var field = null;
  149. switch (spFieldParams.type) {
  150. case 'SPFieldText':
  151. field = new SPTextField(spFieldParams);
  152. break;
  153. case 'SPFieldNote':
  154. field = new SPNoteField(spFieldParams);
  155. break;
  156. case 'SPFieldBoolean':
  157. field = new SPBooleanField(spFieldParams);
  158. break;
  159. case 'SPFieldNumber':
  160. field = new SPNumberField(spFieldParams);
  161. break;
  162. case 'SPFieldCurrency':
  163. field = new SPCurrencyField(spFieldParams);
  164. break;
  165. case 'SPFieldFile':
  166. field = new SPFileField(spFieldParams);
  167. break;
  168. case 'SPFieldDateTime':
  169. field = new SPDateTimeField(spFieldParams);
  170. break;
  171. case 'SPFieldChoice':
  172. case 'SPFieldMultiChoice':
  173. field = new SPChoiceField(spFieldParams);
  174. break;
  175. case 'SPFieldURL':
  176. field = new SPURLField(spFieldParams);
  177. break;
  178. case 'SPFieldUser':
  179. case 'SPFieldUserMulti':
  180. field = new SPUserField(spFieldParams);
  181. break;
  182. case 'SPFieldLookup':
  183. field = new SPLookupField(spFieldParams);
  184. break;
  185. case 'SPFieldLookupMulti':
  186. field = new SPLookupMultiField(spFieldParams);
  187. break;
  188. default:
  189. field = new SPField(spFieldParams);
  190. break;
  191. }
  192. return field;
  193. }
  194. function createSPField(spFieldParams) {
  195. var field = null;
  196. try {
  197. if (null === spFieldParams.controlsCell) {
  198. // the only time this property will NOT be null is in survey forms
  199. spFieldParams.controlsCell = spFieldParams.labelCell.next();
  200. // use nextSibling?
  201. }
  202. spFieldParams.type = getSPFieldType(spFieldParams.controlsCell);
  203. // if we can't get the type then we can't create the field
  204. if (null === spFieldParams.type) {
  205. return null;
  206. }
  207. field = getSPFieldFromType(spFieldParams);
  208. } catch (e) {
  209. log('createSPField: Error creating field for ' + spFieldParams.name, e);
  210. }
  211. return field;
  212. }
  213. function getFieldParams(elemTD, surveyElemTD, isSurveyForm) {
  214. var fieldParams = null, fieldName = 'Unknown field', elemLabel, isRequired;
  215. try {
  216. if (isSurveyForm) {
  217. elemLabel = elemTD;
  218. } else {
  219. // navigate TD -> ??
  220. elemLabel = elemTD.firstDescendant();
  221. if (null === elemLabel || elemLabel.nodeName === 'NOBR') {
  222. return null; // attachments row not currently supported
  223. }
  224. }
  225. fieldName = (elemLabel.getTextContent()).strip();
  226. isRequired = fieldName.endsWith(' *');
  227. if (true === isRequired) {
  228. fieldName = fieldName.substring(0, fieldName.length - 2);
  229. }
  230. fieldParams = {
  231. 'name': fieldName,
  232. 'label': $(elemLabel),
  233. 'labelRow': $(elemTD.parentNode),
  234. 'labelCell': elemTD,
  235. 'isRequired': isRequired,
  236. 'controlsRow': Object.isUndefined(surveyElemTD) ? null : $(surveyElemTD.parentNode),
  237. 'controlsCell': Object.isUndefined(surveyElemTD) ? null : surveyElemTD,
  238. 'type': null,
  239. 'spField': null
  240. };
  241. } catch (e) {
  242. log('getFieldParams: Error getting field parameters ' + fieldName, e);
  243. }
  244. return fieldParams;
  245. }
  246. function lazyLoadSPFields() {
  247. if (null === _fieldsHashtable) {
  248. var i, fieldParams,
  249. fieldElements = $$('table.ms-formtable td.ms-formlabel'),
  250. surveyElements = $$('table.ms-formtable td.ms-formbodysurvey'),
  251. len = fieldElements.length;
  252. _isSurveyForm = (surveyElements.length > 0);
  253. _fieldsHashtable = new Hash();
  254. for (i = 0; i < len; i += 1) {
  255. fieldParams = getFieldParams(fieldElements[i], surveyElements[i], _isSurveyForm);
  256. if (null !== fieldParams) {
  257. _fieldsHashtable.set(fieldParams.name, fieldParams);
  258. }
  259. }
  260. }
  261. }
  262. function toggleSPFieldRows(labelRow, controlsRow, bShowField) {
  263. // controlsRow is populated on survey forms (null otherwise)
  264. if (bShowField) {
  265. labelRow.show();
  266. if (null !== controlsRow) {
  267. controlsRow.show();
  268. }
  269. } else {
  270. labelRow.hide();
  271. if (null !== controlsRow) {
  272. controlsRow.hide();
  273. }
  274. }
  275. }
  276. function toggleSPField(strFieldName, bShowField) {
  277. lazyLoadSPFields();
  278. var fieldParams = _fieldsHashtable.get(strFieldName);
  279. if (Object.isUndefined(fieldParams)) {
  280. log('toggleSPField: Unable to find a SPField named ' + strFieldName + ' - ' + bShowField);
  281. return;
  282. }
  283. toggleSPFieldRows(fieldParams.labelRow, fieldParams.controlsRow, bShowField);
  284. }
  285. function updateReadOnlyLabel(spField, value) {
  286. if (spField.ReadOnlyLabel) {
  287. spField.ReadOnlyLabel.update(spField.GetValue());
  288. }
  289. }
  290. function makeReadOnly(spField, htmlToInsert) {
  291. try {
  292. Element.hide(spField.Controls);
  293. if (null === spField.ReadOnlyLabel) {
  294. spField.ReadOnlyLabel = new Element('div');
  295. spField.ReadOnlyLabel.addClassName('sputility-readonly');
  296. Element.insert(spField.Controls, { after: spField.ReadOnlyLabel });
  297. }
  298. spField.ReadOnlyLabel.update(htmlToInsert);
  299. spField.ReadOnlyLabel.show();
  300. } catch (ex) {
  301. alert('Error making ' + spField.Name + ' read only. ' + ex.toString());
  302. }
  303. return spField;
  304. }
  305. function arrayToSemicolonList(arr) {
  306. var text = '';
  307. arr.each(function (value) {
  308. text += value + '; ';
  309. });
  310. if (text.length > 2) {
  311. text = text.substring(0, text.length - 2);
  312. }
  313. return text;
  314. }
  315. /*
  316. * SPUtility Classes
  317. **/
  318. /*
  319. * SPField class
  320. * Contains all of the common properties and functions used by the specialized
  321. * sub-classes. Typically, this should not be intantiated directly.
  322. */
  323. SPField = Class.create({
  324. initialize: function (fieldParams) {
  325. // Public Properties
  326. this.Label = fieldParams.label;
  327. this.LabelRow = fieldParams.labelRow;
  328. this.Name = fieldParams.name;
  329. this.IsRequired = fieldParams.isRequired;
  330. this.Type = fieldParams.type;
  331. this.Controls = fieldParams.controlsCell.firstDescendant();
  332. this.ControlsRow = fieldParams.controlsRow;
  333. this.ReadOnlyLabel = null;
  334. },
  335. /*
  336. * Public SPField Methods
  337. */
  338. Show: function () {
  339. toggleSPFieldRows(this.LabelRow, this.ControlsRow, true);
  340. return this;
  341. },
  342. Hide: function () {
  343. toggleSPFieldRows(this.LabelRow, this.ControlsRow, false);
  344. return this;
  345. },
  346. MakeReadOnly: function () {
  347. return makeReadOnly(this, this.GetValue().toString());
  348. },
  349. MakeEditable: function () {
  350. try {
  351. Element.show(this.Controls);
  352. if (null !== this.ReadOnlyLabel) {
  353. this.ReadOnlyLabel.hide();
  354. }
  355. } catch (ex) {
  356. alert('Error making ' + this.Name + ' editable. ' + ex.toString());
  357. }
  358. return this;
  359. },
  360. toString: function () {
  361. return this.Name;
  362. },
  363. /*
  364. * Public SPField Override Methods
  365. * All of the below methods need to be implemented in each sub-class
  366. */
  367. GetValue: function () {
  368. throw 'GetValue not yet implemented for ' + this.Type + ' in ' + this.Name;
  369. },
  370. SetValue: function (value) {
  371. throw 'SetValue not yet implemented for ' + this.Type + ' in ' + this.Name;
  372. }
  373. });
  374. /*
  375. * SPTextField class
  376. * Supports Single line of text and Currency fields (base class for number fields)
  377. */
  378. SPTextField = Class.create(SPField, {
  379. initialize: function ($super, spParams) {
  380. $super(spParams);
  381. this.Textbox = getInputControl(this);
  382. },
  383. /*
  384. * SPTextField Public Methods
  385. * Overrides SPField class methods.
  386. */
  387. GetValue: function () {
  388. return this.Textbox.getValue();
  389. },
  390. SetValue: function (value) {
  391. this.Textbox.setValue(value);
  392. updateReadOnlyLabel(this);
  393. return this;
  394. }
  395. });
  396. /*
  397. * SPLookupField class
  398. * Supports single select lookup fields
  399. */
  400. SPLookupField = Class.create(SPField, {
  401. initialize: function ($super, spParams) {
  402. $super(spParams);
  403. var controls = this.Controls.select('input');
  404. if (1 === controls.length) {
  405. // autocomplete lookup
  406. this.Textbox = controls[0];
  407. this.GetValue = function () {
  408. return this.Textbox.getValue();
  409. };
  410. this.SetValue = function (value) {
  411. var choices, hash;
  412. if (Object.isNumber(value)) {
  413. // a list item ID was passed to the function so attempt to lookup the text value
  414. choices = this.Textbox.readAttribute('choices');
  415. hash = new Hash();
  416. // JSLint error here but not much I can do...
  417. choices.scan(/(([^\|]|\|\|)+)\|(\d+)/, function (match) {
  418. hash.set(match[3], match[1].replace(/\|\|/g, '|'));
  419. });
  420. this.Textbox.setValue(hash.get(value.toString()));
  421. } else {
  422. this.Textbox.setValue(value);
  423. }
  424. updateReadOnlyLabel(this);
  425. return this;
  426. };
  427. } else {
  428. controls = this.Controls.select('select');
  429. if (1 === controls.length) {
  430. // regular dropdown lookup
  431. this.Dropdown = controls[0];
  432. this.GetValue = function () {
  433. return this.Dropdown.options[this.Dropdown.selectedIndex].text;
  434. };
  435. this.SetValue = function (value) {
  436. if (Object.isNumber(value)) {
  437. this.Dropdown.setValue(value);
  438. } else {
  439. var i, numOptions;
  440. // need to set the dropdown based on text
  441. numOptions = this.Dropdown.options.length;
  442. for (i = 0; i < numOptions; i += 1) {
  443. if (this.Dropdown.options[i].text === value) {
  444. this.Dropdown.selectedIndex = i;
  445. break;
  446. }
  447. }
  448. }
  449. updateReadOnlyLabel(this);
  450. return this;
  451. };
  452. }
  453. }
  454. }
  455. });
  456. /*
  457. * SPLookupMultiField class
  458. * Supports multi select lookup fields
  459. */
  460. SPLookupMultiField = Class.create(SPField, {
  461. initialize: function ($super, spParams) {
  462. $super(spParams);
  463. var controls = this.Controls.select('select');
  464. if (2 === controls.length) {
  465. // multi-select lookup
  466. this.ListChoices = controls[0];
  467. this.ListSelections = controls[1];
  468. controls = this.Controls.select('button');
  469. this.ButtonAdd = controls[0];
  470. this.ButtonRemove = controls[1];
  471. this.GetValue = function () {
  472. var values = [], i, numOptions;
  473. numOptions = this.ListSelections.options.length;
  474. for (i = 0; i < numOptions; i += 1) {
  475. values.push(this.ListSelections.options[i].text);
  476. }
  477. return values;
  478. };
  479. // display as semicolon delimited list
  480. this.MakeReadOnly = function (options) {
  481. return makeReadOnly(this, arrayToSemicolonList(this.GetValue()));
  482. };
  483. this.SetValue = function (value, addValue) {
  484. if (Object.isUndefined(addValue)) {
  485. addValue = true;
  486. }
  487. var i, option, options, numOptions, funcAction;
  488. if (addValue) {
  489. options = this.ListChoices.options;
  490. funcAction = this.ButtonAdd.onclick;
  491. } else {
  492. options = this.ListSelections.options;
  493. funcAction = this.ButtonRemove.onclick;
  494. }
  495. numOptions = options.length;
  496. // select the value
  497. if (Object.isNumber(value)) {
  498. value = value.toString();
  499. for (i = 0; i < numOptions; i += 1) {
  500. option = options[i];
  501. // deliberate fuzzy comparison
  502. if (option.value === value) {
  503. option.selected = true;
  504. } else {
  505. option.selected = false;
  506. }
  507. }
  508. } else {
  509. for (i = 0; i < numOptions; i += 1) {
  510. option = options[i];
  511. // deliberate fuzzy comparison
  512. if (option.text === value) {
  513. option.selected = true;
  514. } else {
  515. option.selected = false;
  516. }
  517. }
  518. }
  519. funcAction(); // add or remove the value
  520. updateReadOnlyLabel(this);
  521. return this;
  522. };
  523. }
  524. }
  525. });
  526. /*
  527. * SPNoteField class
  528. * Supports rich text fields (SPFieldNote)
  529. */
  530. SPNoteField = Class.create(SPField, {
  531. initialize: function ($super, spParams) {
  532. $super(spParams);
  533. this.Textbox = null;
  534. var controls = this.Controls.select('textarea');
  535. if (1 === controls.length) {
  536. this.Textbox = controls[0];
  537. }
  538. this.IsRichText = (RTE_GetEditorIFrame(this.Textbox.id) !== null);
  539. if (this.IsRichText) {
  540. // RTE functions are defined in layouts/1033/form.js
  541. this.GetValue = function () {
  542. return RTE_GetIFrameContents(this.Textbox.id);
  543. };
  544. this.SetValue = function (value) {
  545. this.Textbox.setValue(value);
  546. RTE_TransferTextAreaContentsToIFrame(this.Textbox.id);
  547. updateReadOnlyLabel(this);
  548. return this;
  549. };
  550. } else {
  551. this.GetValue = function () {
  552. return this.Textbox.getValue();
  553. };
  554. this.SetValue = function (value) {
  555. this.Textbox.setValue(value);
  556. updateReadOnlyLabel(this);
  557. return this;
  558. };
  559. }
  560. }
  561. });
  562. /*
  563. * SPBooleanField class
  564. * Supports yes/no fields (SPFieldBoolean)
  565. */
  566. SPBooleanField = Class.create(SPField, {
  567. initialize: function ($super, spParams) {
  568. $super(spParams);
  569. this.Checkbox = getInputControl(this);
  570. },
  571. /*
  572. * SPBooleanField Public Methods
  573. * Overrides SPField class methods.
  574. */
  575. GetValue: function () {
  576. // double negative to return a boolean value
  577. return !!this.Checkbox.getValue();
  578. },
  579. SetValue: function (value) {
  580. this.Checkbox.setValue(value);
  581. updateReadOnlyLabel(this);
  582. return this;
  583. }
  584. });
  585. /*
  586. * SPNumberField class
  587. * Supports Number fields
  588. */
  589. SPNumberField = Class.create(SPTextField, {
  590. initialize: function ($super, spParams) {
  591. $super(spParams);
  592. },
  593. /*
  594. * SPNumberField Public Methods
  595. * Overrides SPTextField class methods.
  596. */
  597. GetValue: function () {
  598. return convertStringToNumber(this.Textbox.getValue());
  599. }
  600. });
  601. /*
  602. * SPCurrencyField class
  603. * Supports currency fields (SPCurrencyField)
  604. */
  605. SPCurrencyField = Class.create(SPNumberField, {
  606. initialize: function ($super, spParams) {
  607. $super(spParams);
  608. this.FormatOptions = {
  609. eventHandler: null,
  610. autoCorrect: false,
  611. decimalPlaces: 2
  612. };
  613. },
  614. Format: function () {
  615. if (this.FormatOptions.autoCorrect) {
  616. this.FormatOptions.eventHandler = function () {
  617. this.SetValue(this.GetFormattedValue());
  618. }.bindAsEventListener(this);
  619. Event.observe(this.Textbox, 'change', this.FormatOptions.eventHandler);
  620. this.FormatOptions.eventHandler(); // run once
  621. } else {
  622. if (this.FormatOptions.eventHandler) {
  623. Event.stopObserving(this.Textbox, 'change', this.FormatOptions.eventHandler);
  624. this.FormatOptions.eventHandler = null;
  625. }
  626. }
  627. },
  628. GetFormattedValue: function () {
  629. var text = this.GetValue();
  630. if (typeof text === "number") {
  631. text = '$' + text.formatMoney(this.FormatOptions.decimalPlaces);
  632. }
  633. return text;
  634. },
  635. // Override the default MakeReadOnly function to allow displaying
  636. // the value with currency symbols
  637. MakeReadOnly: function (options) {
  638. return makeReadOnly(this, this.GetFormattedValue());
  639. }
  640. });
  641. /*
  642. * SPUserField class
  643. * Supports people fields (SPFieldUser)
  644. */
  645. SPUserField = Class.create(SPField, {
  646. initialize: function ($super, spParams) {
  647. $super(spParams);
  648. this.spanUserField = null;
  649. this.upLevelDiv = null;
  650. this.textareaDownLevelTextBox = null;
  651. this.linkCheckNames = null;
  652. this.txtHiddenSpanData = null;
  653. var controls = this.Controls.select('span.ms-usereditor');
  654. if (null !== controls && 1 === controls.length) {
  655. this.spanUserField = controls[0];
  656. this.upLevelDiv = $(this.spanUserField.id + '_upLevelDiv');
  657. this.textareaDownLevelTextBox = $(this.spanUserField.id + '_downlevelTextBox');
  658. this.linkCheckNames = $(this.spanUserField.id + '_checkNames');
  659. this.txtHiddenSpanData = $(this.spanUserField.id + '_hiddenSpanData');
  660. }
  661. },
  662. /*
  663. * SPUserField Public Methods
  664. * Overrides SPField class methods.
  665. */
  666. GetValue: function () {
  667. //this.textareaDownLevelTextBox.getValue()
  668. return this.upLevelDiv.getTextContent();
  669. },
  670. SetValue: function (value) {
  671. if (Prototype.Browser.IE) {
  672. this.upLevelDiv.innerHTML = value;
  673. this.txtHiddenSpanData.setValue(value);
  674. this.linkCheckNames.click();
  675. } else { // FireFox (maybe others?)
  676. this.textareaDownLevelTextBox.setValue(value);
  677. this.linkCheckNames.onclick();
  678. }
  679. updateReadOnlyLabel(this);
  680. return this;
  681. }
  682. });
  683. /*
  684. * SPURLField class
  685. * Supports hyperlink fields (SPFieldURL)
  686. */
  687. SPURLField = Class.create(SPField, {
  688. initialize: function ($super, spParams) {
  689. $super(spParams);
  690. this.TextboxURL = null;
  691. this.TextboxDescription = null;
  692. var controls = this.Controls.select('input');
  693. if (null !== controls && 2 === controls.length) {
  694. this.TextboxURL = controls[0];
  695. this.TextboxDescription = controls[1];
  696. }
  697. },
  698. /*
  699. * SPURLField Public Methods
  700. * Overrides SPField class methods.
  701. */
  702. GetValue: function () {
  703. return [this.TextboxURL.getValue(), this.TextboxDescription.getValue()];
  704. },
  705. SetValue: function (url, description) {
  706. this.TextboxURL.setValue(url);
  707. this.TextboxDescription.setValue(description);
  708. updateReadOnlyLabel(this);
  709. return this;
  710. },
  711. // overriding the default MakeReadOnly function because we have multiple values returned
  712. // and we want to have the hyperlink field show up as a URL
  713. MakeReadOnly: function (options) {
  714. var text, values = this.GetValue();
  715. if (options && true === options.TextOnly) {
  716. text = values[0] + ', ' + values[1];
  717. } else {
  718. text = '<a href="' + values[0] + '">' + values[1] + '</a>';
  719. }
  720. return makeReadOnly(this, text);
  721. }
  722. });
  723. /*
  724. * SPFileField class
  725. * Supports the name field of a Document Library
  726. */
  727. SPFileField = Class.create(SPTextField, {
  728. initialize: function ($super, spParams) {
  729. $super(spParams);
  730. this.FileExtension = this.Textbox.up(0).getTextContent();
  731. },
  732. /*
  733. * SPFileField Public Methods
  734. * Overrides SPField class methods.
  735. */
  736. GetValue: function () {
  737. return this.Textbox.getValue() + this.FileExtension;
  738. }
  739. });
  740. /*
  741. * SPChoiceField class
  742. * Supports single select choice fields that show as either a dropdown or radio buttons
  743. */
  744. SPChoiceField = Class.create(SPField, {
  745. initialize: function ($super, spParams) {
  746. var FILL_IN_VALUE = 'Specify your own value:',
  747. CHECKBOX_SELECTOR = 'input[type="checkbox"]',
  748. RADIO_SELECTOR = 'input[type="radio"]',
  749. controls = null;
  750. $super(spParams);
  751. this.FillInTextbox = this.Controls.select('input[type="text"]');
  752. if (this.FillInTextbox.length === 1) {
  753. this.FillInTextbox = this.FillInTextbox[0];
  754. this.FillInAllowed = true;
  755. this.FillInElement = null;
  756. } else {
  757. this.FillInAllowed = false;
  758. this.FillInTextbox = null;
  759. this.FillInElement = null;
  760. }
  761. // is this a single select or multi-select?
  762. if (this.Type === 'SPFieldChoice') {
  763. // single select choice field using a dropdown
  764. controls = this.Controls.select('select');
  765. if (1 === controls.length) {
  766. this.Dropdown = controls[0];
  767. if (!this.FillInAllowed) {
  768. // dynamically set our getter/setter functions
  769. this.GetValue = function () {
  770. return this.Dropdown.getValue();
  771. };
  772. this.SetValue = function (value) {
  773. this.Dropdown.setValue(value);
  774. updateReadOnlyLabel(this);
  775. return this;
  776. };
  777. } else {
  778. // dropdown with a fill-in value
  779. controls = getHashFromInputControls(this, RADIO_SELECTOR);
  780. this.FillInElement = controls.get(FILL_IN_VALUE);
  781. controls.unset(FILL_IN_VALUE);
  782. this.GetValue = function () {
  783. if (this.FillInElement.checked === true) {
  784. return this.FillInTextbox.getValue();
  785. }
  786. return this.Dropdown.getValue();
  787. };
  788. this.SetValue = function (value) {
  789. var found = false;
  790. found = !Object.isUndefined($A(this.Dropdown.options).find(function (option) { return option.value === value; }));
  791. if (found) {
  792. this.Dropdown.setValue(value);
  793. this.FillInElement.checked = false;
  794. // fires the function to select the radio button
  795. this.Dropdown.onclick();
  796. } else {
  797. this.FillInElement.checked = true;
  798. this.FillInTextbox.setValue(value);
  799. }
  800. updateReadOnlyLabel(this);
  801. return this;
  802. };
  803. }
  804. }
  805. }
  806. // if the field is single select, then we will have already found
  807. // a dropdown control and everything is setup. otherwise we have setup to do
  808. if (Object.isUndefined(this.Dropdown)) {
  809. if (this.Type === 'SPFieldMultiChoice') {
  810. // multi-choice fields use checkboxes
  811. this.Checkboxes = getHashFromInputControls(this, CHECKBOX_SELECTOR);
  812. // remove the fill-in checkbox because we will check it separately
  813. if (this.FillInAllowed) {
  814. this.FillInElement = this.Checkboxes.get(FILL_IN_VALUE);
  815. this.Checkboxes.unset(FILL_IN_VALUE);
  816. }
  817. this.GetValue = function () {
  818. var values = [];
  819. this.Checkboxes.each(function (pair) {
  820. var checkbox = pair.value;
  821. if (checkbox.checked === true) {
  822. values.push(pair.key);
  823. }
  824. });
  825. if (this.FillInAllowed && this.FillInElement.checked === true) {
  826. values.push(this.FillInTextbox.getValue());
  827. }
  828. return values;
  829. };
  830. this.SetValue = function (value, checked) {
  831. // find the radio button we need to set in our hashtable
  832. var checkBox = this.Checkboxes.get(value);
  833. // if couldn't find the element in the hashtable
  834. // and fill-in is allowed, assume they meant the fill-in value
  835. if (Object.isUndefined(checkBox) && this.FillInAllowed) {
  836. checkBox = this.FillInElement;
  837. this.FillInTextbox.setValue(value);
  838. }
  839. if (!Object.isUndefined(checkBox)) {
  840. if (!Object.isUndefined(checked)) {
  841. checkBox.checked = (true === checked);
  842. } else {
  843. checkBox.checked = true;
  844. }
  845. }
  846. updateReadOnlyLabel(this);
  847. return this;
  848. };
  849. // display as semicolon delimited list
  850. this.MakeReadOnly = function (options) {
  851. return makeReadOnly(this, arrayToSemicolonList(this.GetValue()));
  852. };
  853. } else {
  854. this.RadioButtons = getHashFromInputControls(this, RADIO_SELECTOR);
  855. // remove the fill-in radio button because we will check it separately
  856. if (this.FillInAllowed) {
  857. this.FillInElement = this.RadioButtons.get(FILL_IN_VALUE);
  858. this.RadioButtons.unset(FILL_IN_VALUE);
  859. }
  860. this.GetValue = function () {
  861. var value = null;
  862. // find the radio button we need to get in our hashtable
  863. this.RadioButtons.each(function (pair) {
  864. var radioButton = pair.value;
  865. if (true === radioButton.checked) {
  866. value = pair.key;
  867. throw $break;
  868. }
  869. });
  870. if (this.FillInAllowed && value === null && this.FillInElement.checked === true) {
  871. value = this.FillInTextbox.getValue();
  872. }
  873. return value;
  874. };
  875. this.SetValue = function (value) {
  876. // find the radio button we need to set in our hashtable
  877. var radioButton = this.RadioButtons.get(value);
  878. // if couldn't find the element in the hashtable and fill-in
  879. // is allowed, assume they want to set the fill-in value
  880. if (Object.isUndefined(radioButton) && this.FillInAllowed) {
  881. radioButton = this.FillInElement;
  882. this.FillInTextbox.setValue(value);
  883. }
  884. if (!Object.isUndefined(radioButton)) {
  885. radioButton.checked = true;
  886. }
  887. updateReadOnlyLabel(this);
  888. return this;
  889. };
  890. }
  891. }
  892. }
  893. });
  894. /*
  895. * SPDateTimeFieldValue class
  896. * Used to set/get values for SPDateTimeField fields
  897. */
  898. SPDateTimeFieldValue = Class.create({
  899. initialize: function (year, month, day, strHour, strMinute) {
  900. this.Year = year;
  901. this.Month = month;
  902. this.Day = day;
  903. this.Hour = strHour;
  904. this.Minute = strMinute;
  905. this.IsTimeIncluded = !Object.isUndefined(this.Hour) && !Object.isUndefined(this.Minute);
  906. if (this.IsTimeIncluded) {
  907. if (!this.IsValidHour(this.Hour)) {
  908. throw 'Hour parameter is not in the correct format. Needs to be formatted like "1 PM" or "12 AM".';
  909. }
  910. if (!this.IsValidMinute(this.Minute)) {
  911. throw 'Minute parameter is not in the correct format. Needs to be formatted like "00", "05" or "35".';
  912. }
  913. }
  914. },
  915. /*
  916. * SPDateTimeFieldValue Public Methods
  917. */
  918. IsValidDate: function () {
  919. return !Object.isUndefined(this.Year) && !Object.isUndefined(this.Month) && !Object.isUndefined(this.Day);
  920. },
  921. IsValidHour: function (h) {
  922. return !Object.isUndefined(h) && (/^([1-9]|10|11|12) (AM|PM)$/).test(h);
  923. },
  924. IsValidMinute: function (m) {
  925. return !Object.isUndefined(m) && (/^([0-5](0|5))$/).test(m);
  926. },
  927. // returns the part of a date as a string and pads with a 0 if necessary
  928. PadWithZero: function (d) {
  929. if (Object.isUndefined(d) || null === d) {
  930. return '';
  931. }
  932. if (typeof d === 'string') {
  933. d = parseInt(d, 10);
  934. if (isNaN(d)) {
  935. return '';
  936. }
  937. }
  938. if (typeof d === 'number' && d < 10) {
  939. return '0' + d.toString();
  940. }
  941. return d.toString();
  942. },
  943. // transforms a date object into a string
  944. GetShortDateString: function () {
  945. if (!this.IsValidDate()) {
  946. return '';
  947. }
  948. var strDate = this.PadWithZero(this.Month) + "/" +
  949. this.PadWithZero(this.Day) + "/" +
  950. this.PadWithZero(this.Year);
  951. return strDate;
  952. },
  953. toString: function () {
  954. var str = this.GetShortDateString(), arrHour;
  955. if (this.IsValidHour(this.Hour) && this.IsValidMinute(this.Minute)) {
  956. arrHour = this.Hour.split(' ');
  957. str += ' ' + arrHour[0] + ':' + this.Minute + arrHour[1];
  958. }
  959. return str;
  960. }
  961. });
  962. /*
  963. * SPDateTimeField class
  964. * Date and DateTime fields
  965. */
  966. SPDateTimeField = Class.create(SPField, {
  967. initialize: function ($super, spParams) {
  968. $super(spParams);
  969. this.DateTextbox = getInputControl(this);
  970. this.HourDropdown = null;
  971. this.MinuteDropdown = null;
  972. var timeControls = this.Controls.select('select');
  973. if (null !== timeControls && 2 === timeControls.length) {
  974. this.HourDropdown = $(timeControls[0]);
  975. this.MinuteDropdown = $(timeControls[1]);
  976. }
  977. },
  978. /*
  979. * SPDateTimeField Public Methods
  980. * Overrides SPField class methods.
  981. */
  982. GetValue: function () {
  983. var strHour, strMinute, arrShortDate,
  984. strShortDate = this.DateTextbox.getValue();
  985. if (null !== this.HourDropdown && null !== this.MinuteDropdown) {
  986. strHour = this.HourDropdown.getValue();
  987. strMinute = this.MinuteDropdown.getValue();
  988. }
  989. arrShortDate = strShortDate.split('/');
  990. if (arrShortDate.length === 3) {
  991. return new SPDateTimeFieldValue(arrShortDate[2], arrShortDate[0], arrShortDate[1], strHour, strMinute);
  992. }
  993. // empty or invalid date
  994. return '';
  995. },
  996. SetValue: function (year, month, day, strHour, strMinute) {
  997. if (Object.isString(year) && Object.isUndefined(month)) {
  998. // one string param passed to SetValue
  999. // assume they know what they are doing
  1000. this.DateTextbox.setValue(year);
  1001. } else {
  1002. var value = new SPDateTimeFieldValue(year, month, day, strHour, strMinute);
  1003. this.DateTextbox.setValue(value.GetShortDateString());
  1004. if (null !== this.HourDropdown && null !== this.MinuteDropdown) {
  1005. this.HourDropdown.setValue(value.Hour);
  1006. this.MinuteDropdown.setValue(value.Minute);
  1007. }
  1008. }
  1009. updateReadOnlyLabel(this);
  1010. return this;
  1011. }
  1012. });
  1013. /*
  1014. * SPUtility Public Methods
  1015. */
  1016. return {
  1017. // Creates a soap envelope for use with an AJAX call to SharePoint web services
  1018. CreateSoapEnvelope: function (action, namespace, parameters) {
  1019. var soap = '<?xml version="1.0" encoding="utf-8"?>';
  1020. soap += '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">';
  1021. soap += ' <soap:Body>';
  1022. // creat body of the soap envelope
  1023. if (typeof parameters === 'object' && $H(parameters).keys().length > 0) {
  1024. soap += ' <' + action + ' xmlns="' + namespace + '">';
  1025. $H(parameters).each(function (pair) {
  1026. soap += "<" + pair.key + ">" + pair.value + "</" + pair.key + ">";
  1027. });
  1028. soap += ' </' + action + '>';
  1029. } else {
  1030. soap += ' <' + action + ' xmlns="' + namespace + '" />';
  1031. }
  1032. soap += ' </soap:Body>';
  1033. soap += '</soap:Envelope>';
  1034. return soap;
  1035. },
  1036. Debug: function (isDebug) {
  1037. if ('boolean' === typeof isDebug) {
  1038. _debugMode = isDebug;
  1039. }
  1040. return _debugMode;
  1041. },
  1042. // Gets all of the SPFields on the page
  1043. GetSPFields: function () {
  1044. lazyLoadSPFields();
  1045. return _fieldsHashtable;
  1046. },
  1047. // Searches the page for a specific field by name
  1048. GetSPField: function (strFieldName) {
  1049. lazyLoadSPFields();
  1050. var fieldParams = _fieldsHashtable.get(strFieldName);
  1051. if (Object.isUndefined(fieldParams)) {
  1052. log('GetSPField: Unable to find a SPField named ' + strFieldName);
  1053. return null;
  1054. }
  1055. if (fieldParams.spField === null) {
  1056. // field hasn't been initialized yet
  1057. fieldParams.spField = createSPField(fieldParams);
  1058. }
  1059. return fieldParams.spField;
  1060. },
  1061. HideSPField: function (strFieldName) {
  1062. toggleSPField(strFieldName, false);
  1063. },
  1064. ShowSPField: function (strFieldName) {
  1065. toggleSPField(strFieldName, true);
  1066. }
  1067. };
  1068. }());