diff --git a/sharepoint/SharePoint-tests.ts b/sharepoint/SharePoint-tests.ts index 83934008c..0e6b53e54 100644 --- a/sharepoint/SharePoint-tests.ts +++ b/sharepoint/SharePoint-tests.ts @@ -1,5 +1,11 @@ /// +/// +/// +/// + +//code from http://sptypescript.codeplex.com/ +//BasicTasksJSOM.ts // Website tasks function retrieveWebsite(resultpanel:HTMLElement) { var clientContext = SP.ClientContext.get_current(); @@ -522,4 +528,2039 @@ function deleteListItem(resultpanel: HTMLElement) { function errorHandler() { resultpanel.innerHTML = "Request failed: " + arguments[1].get_message(); } -} \ No newline at end of file +} + + + +/** Lightweight client-side rendering template overrides.*/ +module CSR { + + export interface UpdatedValueCallback { + (value: any, fieldSchema?: SPClientTemplates.FieldSchema_InForm): void; + } + + /** Creates new overrides. Call .register() at the end.*/ + export function override(listTemplateType?: number, baseViewId?: number|string): ICSR { + return new csr(listTemplateType, baseViewId) + .onPreRender(hookFormContext) + .onPostRender(fixCsrCustomLayout); + + function hookFormContext(ctx: IFormRenderContexWithHook) { + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.EditForm + || ctx.ControlMode == SPClientTemplates.ClientControlMode.NewForm) { + + for (var i = 0; i < ctx.ListSchema.Field.length; i++) { + var fieldSchemaInForm = ctx.ListSchema.Field[i]; + + if (!ctx.FormContextHook) { + ctx.FormContextHook = {} + + var oldRegisterGetValueCallback = ctx.FormContext.registerGetValueCallback; + ctx.FormContext.registerGetValueCallback = (fieldName, callback) => { + ctx.FormContextHook[fieldName].getValue = callback; + oldRegisterGetValueCallback(fieldName, callback); + }; + + var oldUpdateControlValue = ctx.FormContext.updateControlValue; + ctx.FormContext.updateControlValue = (fieldName: string, value: any) => { + oldUpdateControlValue(fieldName, value); + + var hookedContext = ensureFormContextHookField(ctx.FormContextHook, fieldName); + hookedContext.lastValue = value; + + var updatedCallbacks = ctx.FormContextHook[fieldName].updatedValueCallbacks; + for (var i = 0; i < updatedCallbacks.length; i++) { + updatedCallbacks[i](value, hookedContext.fieldSchema); + } + + } + } + ensureFormContextHookField(ctx.FormContextHook, fieldSchemaInForm.Name).fieldSchema = fieldSchemaInForm; + } + } + } + + function fixCsrCustomLayout(ctx: SPClientTemplates.RenderContext_Form) { + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.Invalid + || ctx.ControlMode == SPClientTemplates.ClientControlMode.View) { + return; + } + + if (ctx.ListSchema.Field.length > 1) { + var wpq = ctx.FormUniqueId; + var webpart = $get('WebPart' + wpq); + var forms = webpart.getElementsByClassName('ms-formtable'); + + if (forms.length > 0) { + var placeholder = $get(wpq + 'ClientFormTopContainer'); + var fragment = document.createDocumentFragment(); + for (var i = 0; i < placeholder.children.length; i++) { + fragment.appendChild(placeholder.children.item(i)); + } + + var form = forms.item(0); + form.parentNode.replaceChild(fragment, form); + } + + var old = ctx.CurrentItem; + ctx.CurrentItem = ctx.ListData.Items[0]; + var fields = ctx.ListSchema.Field; + for (var j = 0; j < fields.length; j++) { + var field = fields[j]; + var pHolderId = wpq + ctx.FormContext.listAttributes.Id + field.Name; + var span = $get(pHolderId); + if (span) { + span.outerHTML = ctx.RenderFieldByName(ctx, field.Name); + } + } + ctx.CurrentItem = old; + } + + } + + + } + + +//typescripttempltes.ts + declare var Strings:any; + export function getFieldValue(ctx: SPClientTemplates.RenderContext_Form, fieldName: string): any { + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.EditForm + || ctx.ControlMode == SPClientTemplates.ClientControlMode.NewForm) { + var contextWithHook = ctx; + if (contextWithHook.FormContextHook + && contextWithHook.FormContextHook[fieldName] + && contextWithHook.FormContextHook[fieldName].getValue) { + return contextWithHook.FormContextHook[fieldName].getValue(); + } + } + return null; + } + + export function getFieldSchema(ctx: SPClientTemplates.RenderContext_Form, fieldName: string): SPClientTemplates.FieldSchema_InForm { + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.EditForm + || ctx.ControlMode == SPClientTemplates.ClientControlMode.NewForm) { + var contextWithHook = ctx; + if (contextWithHook.FormContextHook + && contextWithHook.FormContextHook[fieldName]) { + return contextWithHook.FormContextHook[fieldName].fieldSchema; + } + } + return null; + } + + export function addUpdatedValueCallback(ctx: SPClientTemplates.RenderContext_Form, fieldName: string, callback: UpdatedValueCallback): void { + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.EditForm + || ctx.ControlMode == SPClientTemplates.ClientControlMode.NewForm) { + var contextWithHook = ctx; + if (contextWithHook.FormContextHook) { + var f = ensureFormContextHookField(contextWithHook.FormContextHook, fieldName); + var callbacks = f.updatedValueCallbacks; + if (callbacks.indexOf(callback) == -1) { + callbacks.push(callback); + if (f.lastValue) { + callback(f.lastValue, f.fieldSchema); + } + } + } + } + + } + + export function removeUpdatedValueCallback(ctx: SPClientTemplates.RenderContext_Form, fieldName: string, callback: UpdatedValueCallback): void { + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.EditForm + || ctx.ControlMode == SPClientTemplates.ClientControlMode.NewForm) { + var contextWithHook = ctx; + if (contextWithHook.FormContextHook) { + var callbacks = ensureFormContextHookField(contextWithHook.FormContextHook, fieldName).updatedValueCallbacks; + var index = callbacks.indexOf(callback); + if (index != -1) { + callbacks.splice(index, 1); + } + } + } + } + + export function getControl(schema: SPClientTemplates.FieldSchema_InForm): HTMLInputElement { + var id = schema.Name + '_' + schema.Id + '_$' + schema.FieldType + 'Field'; + //TODO: Handle different input types + return $get(id); + } + + export function getFieldTemplate(field: SPClientTemplates.FieldSchema, mode: SPClientTemplates.ClientControlMode): SPClientTemplates.FieldCallback { + var ctx = { ListSchema: { Field: [field] }, FieldControlModes: {} }; + ctx.FieldControlModes[field.Name] = mode; + var templates = SPClientTemplates.TemplateManager.GetTemplates(ctx); + return templates.Fields[field.Name]; + } + + + class csr implements ICSR, SPClientTemplates.TemplateOverridesOptions { + + public Templates: SPClientTemplates.TemplateOverrides; + public OnPreRender: SPClientTemplates.RenderCallback[]; + public OnPostRender: SPClientTemplates.RenderCallback[]; + private IsRegistered: boolean; + + + constructor(public ListTemplateType?: number, public BaseViewID?: any) { + this.Templates = { Fields: {} }; + this.OnPreRender = [] ; + this.OnPostRender = []; + this.IsRegistered = false; + } + + /* tier 1 methods */ + view(template: any): ICSR { + this.Templates.View = template; + return this; + } + + item(template: any): ICSR { + this.Templates.Item = template; + return this; + } + + header(template: any): ICSR { + this.Templates.Header = template; + return this; + } + + body(template: any): ICSR { + this.Templates.Body = template; + return this; + } + + footer(template: any): ICSR { + this.Templates.Footer = template; + return this; + } + + fieldView(fieldName: string, template: any): ICSR { + this.Templates.Fields[fieldName] = this.Templates.Fields[fieldName] || {}; + this.Templates.Fields[fieldName].View = template; + return this; + } + + fieldDisplay(fieldName: string, template: any): ICSR { + this.Templates.Fields[fieldName] = this.Templates.Fields[fieldName] || {}; + this.Templates.Fields[fieldName].DisplayForm = template; + return this; + } + + fieldNew(fieldName: string, template: any): ICSR { + this.Templates.Fields[fieldName] = this.Templates.Fields[fieldName] || {}; + this.Templates.Fields[fieldName].NewForm = template; + return this; + } + + fieldEdit(fieldName: string, template: any): ICSR { + this.Templates.Fields[fieldName] = this.Templates.Fields[fieldName] || {}; + this.Templates.Fields[fieldName].EditForm = template; + return this; + } + + /* tier 2 methods */ + template(name: string, template: any): ICSR { + this.Templates[name] = template; + return this; + } + + fieldTemplate(fieldName: string, name: string, template: any): ICSR { + this.Templates.Fields[fieldName] = this.Templates.Fields[fieldName] || {}; + this.Templates.Fields[fieldName][name] = template; + return this; + } + + /* common */ + onPreRender(...callbacks: { (ctx: SPClientTemplates.RenderContext): void; }[]): ICSR { + for (var i = 0; i < callbacks.length; i++) { + this.OnPreRender.push(callbacks[i]); + } + return this; + } + + onPostRender(...callbacks: { (ctx: SPClientTemplates.RenderContext): void; }[]): ICSR { + for (var i = 0; i < callbacks.length; i++) { + this.OnPostRender.push(callbacks[i]); + } + return this; + } + + onPreRenderField(field: string, callback: { (schema: SPClientTemplates.FieldSchema, ctx: SPClientTemplates.RenderContext): void; }): ICSR { + return this.onPreRender((ctx: SPClientTemplates.RenderContext) => { + var ctxInView = ctx; + + //ListSchema schma exists in Form and in View render context + var fields = ctxInView.ListSchema.Field; + if (fields) { + for (var i = 0; i < fields.length; i++) { + if (fields[i].Name === field) { + callback(fields[i], ctx); + } + } + } + }); + } + + onPostRenderField(field: string, callback: { (schema: SPClientTemplates.FieldSchema, ctx: SPClientTemplates.RenderContext): void; }): ICSR { + return this.onPostRender((ctx: SPClientTemplates.RenderContext) => { + var ctxInView = ctx; + + //ListSchema schma exists in Form and in View render context + var fields = ctxInView.ListSchema.Field; + if (fields) { + for (var i = 0; i < fields.length; i++) { + if (fields[i].Name === field) { + callback(fields[i], ctx); + } + } + } + }); + } + + makeReadOnly(fieldName: string): ICSR { + return this + .onPreRenderField(fieldName, (schema, ctx) => { + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.Invalid + || ctx.ControlMode == SPClientTemplates.ClientControlMode.DisplayForm) return; + (schema).ReadOnlyField = true; + (schema).ReadOnly = "TRUE"; + + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.View) { + var ctxInView = ctx; + if (ctxInView.inGridMode) { + //TODO: Disable editing in grid mode + + } + + } else { + var ctxInForm = ctx; + if (schema.Type != 'User' && schema.Type != 'UserMulti') { + + var template = getFieldTemplate(schema, SPClientTemplates.ClientControlMode.DisplayForm); + ctxInForm.Templates.Fields[fieldName] = template; + ctxInForm.FormContext.registerGetValueCallback(fieldName, () => ctxInForm.ListData.Items[0][fieldName]); + + } + } + + }) + .onPostRenderField(fieldName, (schema: SPClientTemplates.FieldSchema_InForm_User, ctx) => { + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.EditForm + || ctx.ControlMode == SPClientTemplates.ClientControlMode.NewForm) { + if (schema.Type == 'User' || schema.Type == 'UserMulti') { + SP.SOD.executeFunc('clientpeoplepicker.js', 'SPClientPeoplePicker', () => { + var topSpanId = schema.Name + '_' + schema.Id + '_$ClientPeoplePicker'; + var retryCount = 10; + var callback = () => { + var pp = SPClientPeoplePicker.SPClientPeoplePickerDict[topSpanId]; + if (!pp) { + if (retryCount--) setTimeout(callback, 1); + } else { + pp.SetEnabledState(false); + pp.DeleteProcessedUser = function () { }; + } + }; + callback(); + }); + } + } + }); + } + + makeHidden(fieldName: string): ICSR { + return this.onPreRenderField(fieldName, (schema, ctx) => { + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.Invalid) return; + (schema).Hidden = true; + + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.View) { + var ctxInView = ctx; + + if (ctxInView.inGridMode) { + //TODO: Hide item in grid mode + } else { + ctxInView.ListSchema.Field.splice(ctxInView.ListSchema.Field.indexOf(schema), 1); + } + + } else { + var ctxInForm = ctx; + + var pHolderId = ctxInForm.FormUniqueId + ctxInForm.FormContext.listAttributes.Id + fieldName; + var placeholder = $get(pHolderId); + var current = placeholder; + while (current.tagName.toUpperCase() !== "TR") { + current = current.parentElement; + } + var row = current; + row.style.display = 'none'; + + } + + }); + } + + filteredLookup(fieldName: string, camlFilter: string, listname?: string, lookupField?: string): ICSR { + + + return this.fieldEdit(fieldName, SPFieldCascadedLookup_Edit) + .fieldNew(fieldName, SPFieldCascadedLookup_Edit); + + + function SPFieldCascadedLookup_Edit(rCtx: SPClientTemplates.RenderContext_FieldInForm) { + + var parseRegex = /\{[^\}]+\}/g; + var dependencyExpressions: string[] = []; + var result: RegExpExecArray; + while ((result = parseRegex.exec(camlFilter))) { + dependencyExpressions.push(stripBraces(result[0])); + } + var dependencyValues: { [expr: string]: string } = {}; + + var _dropdownElt: HTMLSelectElement; + var _myData: SPClientTemplates.ClientFormContext; + + + if (rCtx == null) + return ''; + _myData = SPClientTemplates.Utility.GetFormContextForCurrentField(rCtx); + + if (_myData == null || _myData.fieldSchema == null) + return ''; + + + var _schema = _myData.fieldSchema; + + var validators = new SPClientForms.ClientValidation.ValidatorSet(); + validators.RegisterValidator(new BooleanValueValidator(() => _optionsLoaded, "Wait until lookup values loaded and try again")); + + if (_myData.fieldSchema.Required) { + validators.RegisterValidator(new SPClientForms.ClientValidation.RequiredValidator()); + } + _myData.registerClientValidator(_myData.fieldName, validators); + + var _dropdownId = _myData.fieldName + '_' + _myData.fieldSchema.Id + '_$LookupField'; + var _valueStr = _myData.fieldValue != null ? _myData.fieldValue : ''; + var _selectedValue = SPClientTemplates.Utility.ParseLookupValue(_valueStr).LookupId; + var _noValueSelected = _selectedValue == 0; + var _optionsLoaded = false; + var pendingLoads = 0; + + if (_noValueSelected) + _valueStr = ''; + + _myData.registerInitCallback(_myData.fieldName, InitLookupControl); + + _myData.registerFocusCallback(_myData.fieldName, function () { + if (_dropdownElt != null) + _dropdownElt.focus(); + }); + _myData.registerValidationErrorCallback(_myData.fieldName, function (errorResult) { + SPFormControl_AppendValidationErrorMessage(_dropdownId, errorResult); + }); + _myData.registerGetValueCallback(_myData.fieldName, GetCurrentLookupValue); + _myData.updateControlValue(_myData.fieldName, _valueStr); + + return BuildLookupDropdownControl(); + + function InitLookupControl() { + _dropdownElt = document.getElementById(_dropdownId); + if (_dropdownElt != null) + AddEvtHandler(_dropdownElt, "onchange", OnLookupValueChanged); + + SP.SOD.executeFunc('sp.js', 'SP.ClientContext', () => { + bindDependentControls(dependencyExpressions); + loadOptions(true); + }); + } + + + function BuildLookupDropdownControl() { + var result = ''; + result += '
'; + return result; + } + + + function OnLookupValueChanged() { + if (_optionsLoaded) { + if (_dropdownElt != null) { + _myData.updateControlValue(_myData.fieldName, GetCurrentLookupValue()); + _selectedValue = parseInt(_dropdownElt.value, 10); + } + } + } + + function GetCurrentLookupValue() { + if (_dropdownElt == null) + return ''; + return _dropdownElt.value == '0' || _dropdownElt.value == '' ? '' : _dropdownElt.value + ';#' + _dropdownElt.options[_dropdownElt.selectedIndex].text; + } + + function stripBraces(input: string): string { + return input.substring(1, input.length - 1); + } + + function getDependencyValue(expr: string, value: string, listId: string, expressionParts: string[], callback: () => void) { + var isLookupValue = !!listId; + if (isLookupValue) { + var lookup = SPClientTemplates.Utility.ParseLookupValue(value); + if (expressionParts.length == 1 && expressionParts[0] == 'Value') { + value = lookup.LookupValue; + expressionParts.shift(); + } else { + value = lookup.LookupId.toString(); + } + } + + if (expressionParts.length == 0) { + dependencyValues[expr] = value; + callback(); + } else { + var ctx = SP.ClientContext.get_current(); + var web = ctx.get_web(); + //TODO: Handle lookup to another web + var list = web.get_lists().getById(listId); + var item = list.getItemById(parseInt(value, 10)); + var field = list.get_fields().getByInternalNameOrTitle(expressionParts.shift()); + ctx.load(item); + ctx.load(field); + + ctx.executeQueryAsync((o, e) => { + var value = item.get_item(field.get_internalName()); + + if (field.get_typeAsString() == 'Lookup') { + field = ctx.castTo(field, SP.FieldLookup); + var lookup = (value); + value = lookup.get_lookupId() + ';#' + lookup.get_lookupValue(); + listId = (field).get_lookupList(); + } + + getDependencyValue(expr, value, listId, expressionParts, callback); + + }, (o, args) => { console.log(args.get_message()); }); + } + } + + function bindDependentControls(dependencyExpressions: string[]) { + dependencyExpressions.forEach(expr => { + var exprParts = expr.split("."); + var field = exprParts.shift(); + + CSR.addUpdatedValueCallback(rCtx, field, + (v, s) => { + getDependencyValue(expr, v, + (s).LookupListId, + exprParts.slice(0), + loadOptions); + }); + + }); + } + + + function loadOptions(isFirstLoad?: boolean) { + _optionsLoaded = false; + pendingLoads++; + + var ctx = SP.ClientContext.get_current(); + //TODO: Handle lookup to another web + var web = ctx.get_web(); + var listId = _schema.LookupListId; + var list = !listname ? web.get_lists().getById(listId) : web.get_lists().getByTitle(listname); + var query = new SP.CamlQuery(); + + var predicate = camlFilter.replace(parseRegex, (v, a) => { + var expr = stripBraces(v); + return dependencyValues[expr] ? dependencyValues[expr] : ''; + }); + + //TODO: Handle ShowField attribure + if (predicate.substr(0, 5) == '' + + predicate + + ' ' + + ''); + } + var results = list.getItems(query); + ctx.load(results); + + + ctx.executeQueryAsync((o, e) => { + var selected = false; + + while (_dropdownElt.options.length) { + _dropdownElt.options.remove(0); + } + + if (!_schema.Required) { + var defaultOpt = new Option(Strings.STS.L_LookupFieldNoneOption, '0', selected, selected); + _dropdownElt.options.add(defaultOpt); + selected = _selectedValue == 0; + } + var isEmptyList = true; + + var enumerator = results.getEnumerator(); + while (enumerator.moveNext()) { + var c = enumerator.get_current(); + var id: number; + var text: string; + + if (!lookupField) { + id = c.get_id(); + text = c.get_item('Title'); + } else { + var value = c.get_item(lookupField); + id = value.get_lookupId(); + text = value.get_lookupValue(); + } + var isSelected = _selectedValue == id; + if (isSelected) { + selected = true; + } + var opt = new Option(text, id.toString(), isSelected, isSelected); + _dropdownElt.options.add(opt); + isEmptyList = false; + } + pendingLoads--; + _optionsLoaded = true; + if (!pendingLoads) { + if (isFirstLoad) { + if (_selectedValue == 0 && !selected) { + _dropdownElt.selectedIndex = 0; + OnLookupValueChanged(); + } + } else { + if (_selectedValue != 0 && !selected) { + _dropdownElt.selectedIndex = 0; + } + OnLookupValueChanged(); + } + } + + + }, (o, args) => { console.log(args.get_message()); }); + } + } + + } + + koEditField(fieldName: string, template: string, vm: IKoFieldInForm, dependencyFields?: string[]): ICSR { + return this.fieldEdit(fieldName, koEditField_Edit) + .fieldNew(fieldName, koEditField_Edit); + + + function koEditField_Edit(rCtx: SPClientTemplates.RenderContext_FieldInForm) { + if (rCtx == null) + return ''; + var _myData = SPClientTemplates.Utility.GetFormContextForCurrentField(rCtx); + + if (_myData == null || _myData.fieldSchema == null) + return ''; + var elementId = _myData.fieldName + '_' + _myData.fieldSchema.Id + '_$' + _myData.fieldSchema.Type; + + vm.renderingContext = rCtx; + + + if (dependencyFields) { + dependencyFields.forEach(dependencyField => { + if (!vm[dependencyField]) { + vm[dependencyField] = ko.observable(CSR.getFieldValue(rCtx, dependencyField)); + } + CSR.addUpdatedValueCallback(rCtx, dependencyField, v => { + vm[dependencyField](v); + }); + }); + } + + + if (!vm.value) { + vm.value = ko.observable(); + } + + vm.value.subscribe(v => { _myData.updateControlValue(fieldName, v); }); + _myData.registerGetValueCallback(fieldName, () => vm.value()); + + + _myData.registerInitCallback(fieldName, () => { + ko.applyBindings(vm, $get(elementId)); + }); + + return '
'+template+'
'; + } + } + + computedValue(targetField: string, transform: (...values: string[]) => string, ...sourceField: string[]): ICSR { + var dependentValues: { [field: string]: string } = {}; + + return this.onPostRenderField(targetField, (schema, ctx: SPClientTemplates.RenderContext_FieldInForm) => { + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.EditForm + || ctx.ControlMode == SPClientTemplates.ClientControlMode.NewForm) { + var targetControl = CSR.getControl(schema); + sourceField.forEach((field) => { + CSR.addUpdatedValueCallback(ctx, field, v => { + dependentValues[field] = v; + targetControl.value = transform.apply(this, + sourceField.map(n => dependentValues[n] || '')); + + }); + }); + } + }); + } + + setInitialValue(fieldName: string, value: any, ignoreNull?: boolean): ICSR { + if (value || !ignoreNull) { + return this.onPreRenderField(fieldName, (schema, ctx: SPClientTemplates.RenderContext_FieldInForm) => { + ctx.ListData.Items[0][fieldName] = value; + }); + } else { + return this; + } + } + + + autofill(fieldName: string, init: (ctx: IAutoFillFieldContext) => () => void): ICSR { + return this + .fieldNew(fieldName, SPFieldLookup_Autofill_Edit) + .fieldEdit(fieldName, SPFieldLookup_Autofill_Edit); + + function SPFieldLookup_Autofill_Edit(rCtx: SPClientTemplates.RenderContext_FieldInForm) { + if (rCtx == null) + return ''; + var _myData = SPClientTemplates.Utility.GetFormContextForCurrentField(rCtx); + + if (_myData == null || _myData.fieldSchema == null) + return ''; + + var _autoFillControl: SPClientAutoFill; + var _textInputElt: HTMLInputElement; + var _textInputId = _myData.fieldName + '_' + _myData.fieldSchema.Id + '_$' + _myData.fieldSchema.Type + 'Field'; + var _autofillContainerId = _myData.fieldName + '_' + _myData.fieldSchema.Id + '_$AutoFill'; + + var validators = new SPClientForms.ClientValidation.ValidatorSet(); + if (_myData.fieldSchema.Required) { + validators.RegisterValidator(new SPClientForms.ClientValidation.RequiredValidator()); + } + _myData.registerClientValidator(_myData.fieldName, validators); + + _myData.registerInitCallback(_myData.fieldName, initAutoFillControl); + _myData.registerFocusCallback(_myData.fieldName, function () { + if (_textInputElt != null) + _textInputElt.focus(); + }); + _myData.registerValidationErrorCallback(_myData.fieldName, function (errorResult) { + SPFormControl_AppendValidationErrorMessage(_textInputId, errorResult); + }); + _myData.registerGetValueCallback(_myData.fieldName, () => _myData.fieldValue); + _myData.updateControlValue(_myData.fieldName, _myData.fieldValue); + + return buildAutoFillControl(); + + function initAutoFillControl() { + _textInputElt = document.getElementById(_textInputId); + + SP.SOD.executeFunc("autofill.js", "SPClientAutoFill", () => { + _autoFillControl = new SPClientAutoFill(_textInputId, _autofillContainerId, (_) => callback()); + var callback = init({ + renderContext: rCtx, + fieldContext: _myData, + autofill: _autoFillControl, + control: _textInputElt, + }); + + //_autoFillControl.AutoFillMinTextLength = 2; + //_autoFillControl.VisibleItemCount = 15; + //_autoFillControl.AutoFillTimeout = 500; + }); + + } + //function OnPopulate(targetElement: HTMLInputElement) { + + //} + + //function OnLookupValueChanged() { + // _myData.updateControlValue(_myData.fieldName, GetCurrentLookupValue()); + //} + //function GetCurrentLookupValue() { + // return _valueStr; + //} + function buildAutoFillControl() { + var result: string[] = []; + result.push('
'); + result.push(''); + + result.push("
"); + result.push("
"); + + return result.join(""); + } + } + + + } + + seachLookup(fieldName: string): ICSR { + return this.autofill(fieldName, (ctx: IAutoFillFieldContext) => { + var _myData = ctx.fieldContext; + var _schema = _myData.fieldSchema; + if (_myData.fieldSchema.Type != 'Lookup') { + return null; + } + + var _valueStr = _myData.fieldValue != null ? _myData.fieldValue : ''; + var _selectedValue = SPClientTemplates.Utility.ParseLookupValue(_valueStr); + var _noValueSelected = _selectedValue.LookupId == 0; + ctx.control.value = _selectedValue.LookupValue; + $addHandler(ctx.control, "blur", _ => { + if (ctx.control.value == '') { + _myData.fieldValue = ''; + _myData.updateControlValue(fieldName, _myData.fieldValue); + } + }); + + if (_noValueSelected) + _myData.fieldValue = ''; + + var _autoFillControl = ctx.autofill; + _autoFillControl.AutoFillMinTextLength = 2; + _autoFillControl.VisibleItemCount = 15; + _autoFillControl.AutoFillTimeout = 500; + + return () => { + var value = ctx.control.value; + _autoFillControl.PopulateAutoFill([AutoFillOptionBuilder.buildLoadingItem('Please wait...')], onSelectItem); + + SP.SOD.executeFunc("sp.search.js", "Microsoft.SharePoint.Client.Search.Query", () => { + var Search = Microsoft.SharePoint.Client.Search.Query; + var ctx = SP.ClientContext.get_current(); + var query = new Search.KeywordQuery(ctx); + query.set_rowLimit(_autoFillControl.VisibleItemCount); + query.set_queryText('contentclass:STS_ListItem ListID:{' + _schema.LookupListId + '} ' + value); + var selectProps = query.get_selectProperties(); + selectProps.clear(); + //TODO: Handle ShowField attribute + selectProps.add('Title'); + selectProps.add('ListItemId'); + var executor = new Search.SearchExecutor(ctx); + var result = executor.executeQuery(query); + ctx.executeQueryAsync( + () => { + //TODO: Discover proper way to load collection + var tableCollection = new Search.ResultTableCollection(); + tableCollection.initPropertiesFromJson(result.get_value()); + + var relevantResults = tableCollection.get_item(0); + var rows = relevantResults.get_resultRows(); + + var items = []; + for (var i = 0; i < rows.length; i++) { + items.push(AutoFillOptionBuilder.buildOptionItem(parseInt(rows[i]["ListItemId"], 10), rows[i]["Title"])); + } + + items.push(AutoFillOptionBuilder.buildSeparatorItem()); + + if (relevantResults.get_totalRows() == 0) + items.push(AutoFillOptionBuilder.buildFooterItem("No results. Please refine your query.")); + else + items.push(AutoFillOptionBuilder.buildFooterItem("Showing " + rows.length + " of" + relevantResults.get_totalRows() + " items!")); + + _autoFillControl.PopulateAutoFill(items, onSelectItem); + + }, + (sender, args) => { + _autoFillControl.PopulateAutoFill([AutoFillOptionBuilder.buildFooterItem("Error executing query/ See log for details.")], onSelectItem); + console.log(args.get_message()); + }); + }); + } + + function onSelectItem(targetInputId, item: ISPClientAutoFillData) { + var targetElement = ctx.control; + targetElement.value = item[SPClientAutoFill.DisplayTextProperty]; + _selectedValue.LookupId = item[SPClientAutoFill.KeyProperty]; + _selectedValue.LookupValue = item[SPClientAutoFill.DisplayTextProperty]; + _myData.fieldValue = item[SPClientAutoFill.KeyProperty] + ';#' + item[SPClientAutoFill.TitleTextProperty]; + _myData.updateControlValue(_myData.fieldSchema.Name, _myData.fieldValue); + } + + }); + } + + lookupAddNew(fieldName: string, prompt: string, showDialog?: boolean, contentTypeId?: string): ICSR { + return this.onPostRenderField(fieldName, + (schema: SPClientTemplates.FieldSchema_InForm_Lookup, ctx: SPClientTemplates.RenderContext_FieldInForm) => { + if (ctx.ControlMode == SPClientTemplates.ClientControlMode.EditForm + || ctx.ControlMode == SPClientTemplates.ClientControlMode.NewForm) + + var control = CSR.getControl(schema); + if (control) { + var weburl = _spPageContextInfo.webServerRelativeUrl; + if (weburl[weburl.length - 1] == '/') { + weburl = weburl.substring(0, weburl.length - 1); + } + var newFormUrl = weburl + '/_layouts/listform.aspx/listform.aspx?PageType=8' + + "&ListId=" + encodeURIComponent('{' + schema.LookupListId + '}'); + if (contentTypeId) { + newFormUrl += '&ContentTypeId=' + contentTypeId; + } + + var link = document.createElement('a'); + link.href = "javascript:NewItem2(event, \'" + newFormUrl + "&Source=" + encodeURIComponent(document.location.href) + "')"; + link.textContent = prompt; + if (control.nextElementSibling) { + control.parentElement.insertBefore(link, control.nextElementSibling); + } else { + control.parentElement.appendChild(link); + } + + if (showDialog) { + $addHandler(link, "click", (e: Sys.UI.DomEvent) => { + SP.SOD.executeFunc('sp.ui.dialog.js', 'SP.UI.ModalDialog.ShowPopupDialog', () => { + SP.UI.ModalDialog.ShowPopupDialog(newFormUrl); + }); + e.stopPropagation(); + e.preventDefault(); + }); + } + } + }); + } + + register() { + if (!this.IsRegistered) { + SPClientTemplates.TemplateManager.RegisterTemplateOverrides(this); + this.IsRegistered = true; + } + } + } + + export class AutoFillOptionBuilder { + + static buildFooterItem(title: string): ISPClientAutoFillData { + var item = {}; + + item[SPClientAutoFill.DisplayTextProperty] = title; + item[SPClientAutoFill.MenuOptionTypeProperty] = SPClientAutoFill.MenuOptionType.Footer; + + return item; + } + + static buildOptionItem(id: number, title: string, displayText?: string, subDisplayText?: string): ISPClientAutoFillData { + + var item = {}; + + item[SPClientAutoFill.KeyProperty] = id; + item[SPClientAutoFill.DisplayTextProperty] = displayText || title; + item[SPClientAutoFill.SubDisplayTextProperty] = subDisplayText; + item[SPClientAutoFill.TitleTextProperty] = title; + item[SPClientAutoFill.MenuOptionTypeProperty] = SPClientAutoFill.MenuOptionType.Option; + + return item; + } + + static buildSeparatorItem(): ISPClientAutoFillData { + var item = {}; + item[SPClientAutoFill.MenuOptionTypeProperty] = SPClientAutoFill.MenuOptionType.Separator; + return item; + } + + static buildLoadingItem(title: string): ISPClientAutoFillData { + var item = {}; + + item[SPClientAutoFill.MenuOptionTypeProperty] = SPClientAutoFill.MenuOptionType.Loading; + item[SPClientAutoFill.DisplayTextProperty] = title; + return item; + } + + } + + /** Lightweight client-side rendering template overrides.*/ + export interface ICSR { + /** Override rendering template. + @param name Name of template to override. + @param template New template. + */ + template(name: string, template: string): ICSR; + + /** Override rendering template. + @param name Name of template to override. + @param template New template. + */ + template(name: string, template: (ctx: SPClientTemplates.RenderContext) => string): ICSR; + + /** Override field rendering template. + @param name Internal name of field to override. + @param name Name of template to override. + @param template New template. + */ + fieldTemplate(field: string, name: string, template: string): ICSR; + + /** Override field rendering template. + @param name Internal name of field to override. + @param name Name of template to override. + @param template New template. + */ + fieldTemplate(field: string, name: string, template: (ctx: SPClientTemplates.RenderContext) => string): ICSR; + + /** Sets pre-render callbacks. Callback called before rendering starts. + @param callbacks pre-render callbacks. + */ + onPreRender(...callbacks: { (ctx: SPClientTemplates.RenderContext): void; }[]): ICSR; + + /** Sets post-render callbacks. Callback called after rendered html inserted to DOM. + @param callbacks post-render callbacks. + */ + onPostRender(...callbacks: { (ctx: SPClientTemplates.RenderContext): void; }[]): ICSR; + + /** Sets pre-render callbacks for field. Callback called before rendering starts. Correctly handles form rendering. + @param fieldName Internal name of the field. + @param callbacks pre-render callbacks. + */ + onPreRenderField(field: string, callback: { (schema: SPClientTemplates.FieldSchema, ctx: SPClientTemplates.RenderContext): void; }): ICSR; + + /** Sets post-render callbacks. Callback called after rendered html inserted to DOM. Correctly handles form rendering. + @param fieldName Internal name of the field. + @param callbacks post-render callbacks. + */ + onPostRenderField(field: string, callback: { (schema: SPClientTemplates.FieldSchema, ctx: SPClientTemplates.RenderContext): void; }): ICSR; + + /** Registers overrides in client-side templating engine.*/ + register(): void; + + /** Override View rendering template. + @param template New view template. + */ + view(template: string): ICSR; + + /** Override View rendering template. + @param template New view template. + */ + view(template: (ctx: SPClientTemplates.RenderContext_InView) => string): ICSR; + view(template: (ctx: SPClientTemplates.RenderContext_Form) => string): ICSR; + + /** Override Item rendering template. + @param template New item template. + */ + item(template: string): ICSR; + + /** Override Item rendering template. + @param template New item template. + */ + item(template: (ctx: SPClientTemplates.RenderContext_ItemInView) => string): ICSR; + item(template: (ctx: SPClientTemplates.RenderContext_Form) => string): ICSR; + + /** Override Header rendering template. + @param template New header template. + */ + header(template: string): ICSR; + + /** Override Header rendering template. + @param template New header template. + */ + header(template: (ctx: SPClientTemplates.RenderContext) => string): ICSR; + + /** Override Body rendering template. + @param template New body template. + */ + body(template: string): ICSR; + + /** Override Body rendering template. + @param template New body template. + */ + body(template: (ctx: SPClientTemplates.RenderContext) => string): ICSR; + + /** Override Footer rendering template. + @param template New footer template. + */ + footer(template: string): ICSR; + + /** Override Footer rendering template. + @param template New footer template. + */ + footer(template: (ctx: SPClientTemplates.RenderContext) => string): ICSR; + + /** Override View rendering template for specified field. + @param fieldName Internal name of the field. + @param template New View template. + */ + fieldView(fieldName: string, template: string): ICSR; + + /** Override View rendering template for specified field. + @param fieldName Internal name of the field. + @param template New View template. + */ + fieldView(fieldName: string, template: (ctx: SPClientTemplates.RenderContext_FieldInView) => string): ICSR; + + /** Override DisplyForm rendering template for specified field. + @param fieldName Internal name of the field. + @param template New DisplyForm template. + */ + fieldDisplay(fieldName: string, template: string): ICSR; + + /** Override DisplyForm rendering template. + @param fieldName Internal name of the field. + @param template New DisplyForm template. + */ + fieldDisplay(fieldName: string, template: (ctx: SPClientTemplates.RenderContext_FieldInForm) => string): ICSR; + + /** Override EditForm rendering template for specified field. + @param fieldName Internal name of the field. + @param template New EditForm template. + */ + fieldEdit(fieldName: string, template: string): ICSR; + + /** Override EditForm rendering template. + @param fieldName Internal name of the field. + @param template New EditForm template. + */ + fieldEdit(fieldName: string, template: (ctx: SPClientTemplates.RenderContext_FieldInForm) => string): ICSR; + + /** Override NewForm rendering template for specified field. + @param fieldName Internal name of the field. + @param template New NewForm template. + */ + fieldNew(fieldName: string, template: string): ICSR; + + /** Override NewForm rendering template. + @param fieldName Internal name of the field. + @param template New NewForm template. + */ + fieldNew(fieldName: string, template: (ctx: SPClientTemplates.RenderContext_FieldInForm) => string): ICSR; + + + /** Set initial value for field. + @param fieldName Internal name of the field. + @param value Initial value for field. + */ + setInitialValue(fieldName: string, value: any): ICSR; + + /** Make field hidden in list view and standard forms. + @param fieldName Internal name of the field. + */ + makeHidden(fieldName: string): ICSR + + + /** Replace New and Edit templates for field to Display template. + @param fieldName Internal name of the field. + */ + makeReadOnly(fieldName: string): ICSR + + /** Create cascaded Lookup Field. + @param fieldName Internal name of the field. + @param camlFilter CAML predicate expression (inside Where clause). Use {FieldName} tokens for dependency fields substitutions. + */ + filteredLookup(fieldName: string, camlFilter: string, listname?: string, lookupField?: string): ICSR + + /** Auto computes text-based field value based on another fields. + @param targetField Internal name of the field. + @param transform Function combines source field values. + @param sourceField Internal names of source fields. + */ + computedValue(targetField: string, transform: (...values: string[]) => string, ...sourceField: string[]): ICSR + + /** Field text value with autocomplete based on autofill.js + @param fieldName Internal name of the field. + @param ctx AutoFill context. + */ + autofill(fieldName: string, init: (ctx: IAutoFillFieldContext) => () => void): ICSR + + /** Replace defult dropdown to search-based autocomplete for Lookup field. + @param fieldName Internal name of the field. + */ + seachLookup(fieldName: string): ICSR; + + /** Adds link to add new value to lookup list. + @param fieldName Internal name of the field. + @param prompt Text to display as a link to add new value. + @param contentTypeID Default content type for new item. + */ + lookupAddNew(fieldName: string, prompt: string, showDialog?: boolean, contentTypeId?: string): ICSR; + + koEditField(fieldName: string, template: string, vm: IKoFieldInForm, dependencyFields?: string[]): ICSR; + + + } + + export interface IAutoFillFieldContext { + renderContext: SPClientTemplates.RenderContext_FieldInForm; + fieldContext: SPClientTemplates.ClientFormContext; + autofill: SPClientAutoFill; + control: HTMLInputElement; + } + + export interface IKoFieldInForm { + renderingContext?:SPClientTemplates.RenderContext_FieldInForm; + value?:KnockoutObservable; + } + + + interface IFormRenderContexWithHook extends SPClientTemplates.RenderContext_FieldInForm { + FormContextHook: IFormContextHook; + } + + interface IFormContextHook { + [fieldName: string]: IFormContextHookField; + } + + interface IFormContextHookField { + fieldSchema?: SPClientTemplates.FieldSchema_InForm; + lastValue?: any; + getValue?: () => any; + updatedValueCallbacks: UpdatedValueCallback[]; + } + + + function ensureFormContextHookField(hook: IFormContextHook, fieldName: string): IFormContextHookField { + return hook[fieldName] = hook[fieldName] || { + updatedValueCallbacks: [] + }; + + } + + class BooleanValueValidator implements SPClientForms.ClientValidation.IValidator { + constructor(public valueGetter: () => boolean, public validationMessage: string) { } + + Validate(value: any): SPClientForms.ClientValidation.ValidationResult { + return new SPClientForms.ClientValidation.ValidationResult(!this.valueGetter(), this.validationMessage); + } + } + +} + +if (typeof SP == 'object' && SP && typeof SP.SOD == 'object' && SP.SOD) { + SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs("typescripttemplates.ts"); +} + + +//mquery.ts + + + + +module spdevlab { + export module mQuery { + export class DynamicTable { + + // private fields + _domContainer:HTMLElement; + _tableContainer:MQueryResultSetElements; + + _rowTemplateId:string = null; + _rowTemplateContent:string = null; + + _options = { + tableCnt: '.spdev-rep-tb', + addCnt: '.spdev-rep-tb-add', + removeCnt: '.spdev-rep-tb-del' + }; + + // public methods + init(domContainer: HTMLElement, options) { + + if (m$.isDefinedAndNotNull(options)) { + m$.extend(this._options, options); + } + + this._initContainers(domContainer); + + this._initRowTemplate(); + this._initEvents(); + this._showUI(); + } + + // private methods + _initContainers(domContainer) { + + this._domContainer = domContainer; + this._tableContainer = m$(this._options.tableCnt, this._domContainer); + } + + _showUI() { + m$(this._domContainer).css("display", ""); + } + + _initEvents() { + + m$(this._options.addCnt, this._domContainer).click(() => { + + if (m$.isDefinedAndNotNull(this._rowTemplateContent)) { + + m$(this._tableContainer).append(this._rowTemplateContent); + + m$("tr:last-child " + this._options.removeCnt, this._tableContainer).click( (e) => { + + var targetElement = e.currentTarget; + var parentRow = m$(targetElement).parents("tr").first(); + + m$(parentRow).remove(); + }); + } + + return false; + }); + } + + _initRowTemplate() { + var templateId = m$(this._tableContainer).attr("template-id"); + + if (m$.isDefinedAndNotNull(templateId)) { + this._rowTemplateId = templateId; + this._rowTemplateContent = DynamicTable._templates[templateId]; + } + } + + static _templates:string[] = []; + static initTables() { + // init templates + m$('script').forEach((template:HTMLElement) => { + + var id = m$(template).attr("dynamic-table-template-id"); + + if (m$.isDefinedAndNotNull(id)) { + DynamicTable._templates[id] = template.innerHTML; + } + }); + + // init tables + m$(".spdev-rep-tb-cnt").forEach( divContainer => { + + var dynamicTable = new DynamicTable(); + + dynamicTable.init(divContainer, { + removeCnt: '.spdev-rep-tb-del-override' + }); + }); + } + + }; + + + } +} + +m$.ready(() => { + spdevlab.mQuery.DynamicTable.initTables(); +}); + + +//whoisapppart.ts + + +module _ { + var queryString = parseQueryString(); + var isIframe = queryString['DisplayMode'] == 'iframe' + var spHostUrl = queryString['SPHostUrl']; + var editmode = Number(queryString['editmode']); + var includeDetails = queryString['boolProp'] == 'true'; + + prepareVisual(); + m$.ready(() => { + loadPeoplePicker('peoplePicker'); + partProperties(); + + if (isIframe) { + partResize(); + } + }); + + //Load the people picker + function loadPeoplePicker(peoplePickerElementId: string) { + var schema: ISPClientPeoplePickerSchema = { + PrincipalAccountType: "User", + AllowMultipleValues: false, + Width: 300, + OnUserResolvedClientScript: onUserResolvedClientScript + } + + SPClientPeoplePicker.InitializeStandalonePeoplePicker(peoplePickerElementId, null, schema); + } + + function onUserResolvedClientScript(el: string, users: ISPClientPeoplePickerEntity[]) { + if (users.length > 0) { + var person = users[0]; + var accountName = person.Key; + + var context = SP.ClientContext.get_current(); + + var peopleManager = new SP.UserProfiles.PeopleManager(context); + var personProperties = peopleManager.getPropertiesFor(accountName); + + context.load(personProperties); + context.executeQueryAsync((sender, args) => { + + $get("basicInfo").style.display = 'block'; + + var userPic = personProperties.get_userProfileProperties()["PictureURL"]; + $get("pic").innerHTML = ' + personProperties.get_displayName() + '; + + $get("name").innerHTML = '' + personProperties.get_displayName() + ''; + $get("email").innerHTML = '' + personProperties.get_email() + ''; + $get("title").innerHTML = personProperties.get_title(); + $get("department").innerHTML = person.EntityData.Department; + $get("phone").innerHTML = person.EntityData.MobilePhone; + + var properties = personProperties.get_userProfileProperties(); + var messageText = ""; + for (var key in properties) { + messageText += "
[" + key + "]: \"" + properties[key] + "\""; + } + $get("detailInfo").innerHTML = messageText; + + if (isIframe) { + partResize(); + } + + }, (sender, args) => { alert('Error: ' + args.get_message()); }); + + } + } + + function partProperties() { + + if (editmode == 1) { + $get("editmodehdr").style.display = "inline"; + $get("content").style.display = "none"; + } + else if (includeDetails) { + $get('detailInfo').style.display = 'block'; + + $get("editmodehdr").style.display = "none"; + $get("content").style.display = "inline"; + } + } + + function partResize() { + var bounds = Sys.UI.DomElement.getBounds(document.body); + parent.postMessage('resize(' + bounds.width + ',' + bounds.height + ')', '*'); + } + + function prepareVisual() { + if (isIframe) { + //Create a Link element for the defaultcss.ashx resource + var linkElement = document.createElement('link'); + linkElement.setAttribute('rel', 'stylesheet'); + linkElement.setAttribute('href', spHostUrl + '/_layouts/15/defaultcss.ashx'); + + //Add the linkElement as a child to the head section of the html + document.head.appendChild(linkElement); + } else { + + m$.ready(() => { + var nav = new SP.UI.Controls.Navigation('navigation', { + appIconUrl: queryString['SPHostLogo'], + appTitle: document.title + }); + nav.setVisible(true); + $get('apppart-notification').style.display = 'block'; + document.body.style.overflow = 'visible'; + }); + } + } + + function parseQueryString() { + var result = {}; + var qs = document.location.search.split('?')[1]; + if (qs) { + var parts = qs.split('&'); + for (var i = 0; i < parts.length; i++) { + if (parts[i]) { + var pair = parts[i].split('='); + result[pair[0]] = decodeURIComponent(pair[1]); + } + } + } + return result; + } +} + +//taxonomy +module SP { + + // Class + export class ClientContextPromise extends SP.ClientContext { + /** To use this function, you must ensure that jQuery and CSOMPromise js files are loaded to the page */ + executeQueryPromise(): JQueryPromise { + var deferred = jQuery.Deferred(); + this.executeQueryAsync(function (sender, args) { + deferred.resolve(sender, args); + }, + function (sender, args) { + deferred.reject(sender, args); + }) + return deferred.promise(); + } + + constructor(serverRelativeUrlOrFullUrl: string) { + super(serverRelativeUrlOrFullUrl); + } + + static get_current(): ClientContextPromise { + return new ClientContextPromise(_spPageContextInfo.siteServerRelativeUrl); + } + + } + +} + +SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs("CSOMPromise.ts"); + +module _ { + var context: SP.ClientContextPromise; + var web: SP.Web; + var site: SP.Site; + var session: SP.Taxonomy.TaxonomySession; + var termStore: SP.Taxonomy.TermStore; + var groups: SP.Taxonomy.TermGroupCollection; + + // This code runs when the DOM is ready and creates a context object + // which is needed to use the SharePoint object model. + // It also wires up the click handlers for the two HTML buttons in Default.aspx. + $(document).ready(function () { + context = SP.ClientContextPromise.get_current(); + site = context.get_site(); + web = context.get_web(); + $('#listExisting').click(function () { listGroups(); }); + $('#createTerms').click(function () { createTerms(); }); + }); + + // When the listExisting button is clicked, start by loading + // a TaxonomySession for the current context. Also get and load + // the associated term store. + function listGroups() { + session = SP.Taxonomy.TaxonomySession.getTaxonomySession(context); + termStore = session.getDefaultSiteCollectionTermStore(); + context.load(session); + context.load(termStore); + context.executeQueryAsync(onListTaxonomySession, onFailListTaxonomySession); + } + + // Runs when the executeQueryAsync method in the listGroups function has succeeded. + // In this case, get and load the groups associated with the term store that we + // know we now have a reference to. + function onListTaxonomySession() { + groups = termStore.get_groups(); + context.load(groups); + context.executeQueryAsync(onRetrieveGroups, onFailRetrieveGroups); + } + + // Runs when the executeQueryAsync method in the onListTaxonomySession function has succeeded. + // In this case, loop through all the groups and add a clickable div element to the report area + // for each group. + // NOTE: We clear the report area first to ensure we have a clean place to write to. + // Also note how we create a click event handler for each div on-the-fly, and that we pass in the + // current group ID to that function. So when the user clicks one of these divs, we will know which + // one was clicked. + function onRetrieveGroups() { + $('#report').children().remove(); + + var groupEnum = groups.getEnumerator(); + + // For each group, we'll build a clickable div. + while (groupEnum.moveNext()) { + (() => { + var currentGroup = groupEnum.get_current(); + var groupName = document.createElement("div"); + groupName.setAttribute("style", "float:none;cursor:pointer"); + var groupID = currentGroup.get_id(); + groupName.setAttribute("id", groupID.toString()); + $(groupName).click(() => showTermSets(groupID)); + groupName.appendChild(document.createTextNode(currentGroup.get_name())); + $('#report').append(groupName); + })(); + } + } + + // This is the function that runs when the user clicks one of the divs + // that we created in the onRetrieveGroups function. We can know which + // div was clicked by interrogating the groupID parameter. So what we'll + // do is retrieve a reference to the group with the same ID as the div, and + // then add the term sets that belong to that group under the div that was clicked. + function showTermSets(groupID: SP.Guid) { + + // First thing is to remnove the divs under the group DIV to ensure we have a clean place to write to. + // The reason we don't clear them all is becuase we want to retain the text node of the + // group div. I.E. that's why we use "parentDiv.childNodes.length>1" as our loop + // controller. + var parentDiv = document.getElementById(groupID.toString()); + while (parentDiv.childNodes.length > 1) { + parentDiv.removeChild(parentDiv.lastChild); + } + + // For each term set, we'll build a clickable div + var currentGroup = groups.getById(groupID); + + // We need to load and populate the matching group first, or the + // term sets that it contains will be inaccessible to our code. + context.load(currentGroup); + var termSets: SP.Taxonomy.TermSetCollection; + context.executeQueryPromise() + .then( + () => { + // The group is now available becuase this is the + // success callback. So now we'll load and populate the + // term set collection. We have to do this before we can + // iterate through the collection, so we can do this + // with the following nested executeQueryAsync method call. + termSets = currentGroup.get_termSets(); + context.load(termSets); + return context.executeQueryPromise() + }) + .then(() => { + // The term sets are now available becuase this is the + // success callback. So now we'll iterate through the collection + // and create the clickable div. Also note how we create a + // click event handler for each div on-the-fly, and that we pass in the + // current group ID and term set ID to that function. So when the user + // clicks one of these divs, we will know which + // one was clicked by its term set ID, and to which group it belongs by its + // group ID. We also pass in the event object, so that we can cancel the bubble + // because this clickable div will be inside a parent clickable div and we + // don't want the parent's event to fire. + var termSetEnum = termSets.getEnumerator(); + while (termSetEnum.moveNext()) { + (() => { + var currentTermSet = termSetEnum.get_current(); + var termSetName = document.createElement("div"); + termSetName.appendChild(document.createTextNode(" + " + currentTermSet.get_name())); + termSetName.setAttribute("style", "float:none;cursor:pointer;"); + var termSetID = currentTermSet.get_id(); + termSetName.setAttribute("id", termSetID.toString()); + $(termSetName).click(e => showTerms(e, groupID, termSetID)); + parentDiv.appendChild(termSetName); + })(); + } + + }) + .fail(() => parentDiv.appendChild(document.createTextNode("An error occurred in loading the term sets for this group"))); + } + + + // This is the function that runs when the user clicks one of the divs + // that we created in the showTermSets function. We can know which + // div was clicked by interrogating the termSetID parameter. So what we'll + // do is retrieve a reference to the term set with the same ID as the div, and + // then add the term that belong to that term set under the div that was clicked. + + function showTerms(event: JQueryEventObject, groupID: SP.Guid, termSetID: SP.Guid) { + + // First, cancel the bubble so that the group div click handler does not also fire + // because that removes all term set divs and we don't want that here. + event.cancelBubble = true; + + // Get a reference to the term set div that was click and + // remove its children (apart from the TextNode that is currently + // showing the term set name. + var parentDiv = document.getElementById(termSetID.toString()); + while (parentDiv.childNodes.length > 1) { + parentDiv.removeChild(parentDiv.lastChild); + } + + // We need to load and populate the matching group first, or the + // term sets that it contains will be inaccessible to our code. + var currentGroup = groups.getById(groupID); + var termSets:SP.Taxonomy.TermSetCollection; + var currentTermSet:SP.Taxonomy.TermSet; + var terms:SP.Taxonomy.TermCollection; + + context.load(currentGroup); + context + .executeQueryPromise() + .then(() => { + // The group is now available becuase this is the + // success callback. So now we'll load and populate the + // term set collection. We have to do this before we can + // iterate through the collection, so we can do this + // with the following nested executeQueryAsync method call. + termSets = currentGroup.get_termSets(); + context.load(termSets); + return context.executeQueryPromise(); + }) + .then(() => { + currentTermSet = termSets.getById(termSetID); + context.load(currentTermSet); + return context.executeQueryPromise(); + }) + .then(() => { + terms = currentTermSet.get_terms(); + context.load(terms); + return context.executeQueryPromise(); + }) + .then(() => { + var termsEnum = terms.getEnumerator(); + while (termsEnum.moveNext()) { + var currentTerm = termsEnum.get_current(); + + var term = document.createElement("div"); + term.appendChild(document.createTextNode(" - " + currentTerm.get_name())); + term.setAttribute("style", "float:none;margin-left:10px;"); + parentDiv.appendChild(term); + } + }) + .fail(() => parentDiv.appendChild(document.createTextNode("An error occurred when trying to retrieve terms in this term set"))); + } + + // Runs when the executeQueryAsync method in the onListTaxonomySession function has failed. + // In this case, clear the report area in the page and tell the user what went wrong. + function onFailRetrieveGroups(sender, args) { + $('#report').children().remove(); + $('#report').append("Failed to retrieve groups. Error:" + args.get_message()); + } + + // Runs when the executeQueryAsync method in the listGroups function has failed. + // In this case, clear the report area in the page and tell the user what went wrong. + function onFailListTaxonomySession(sender, args) { + $('#report').children().remove(); + $('#report').append("Failed to get session. Error: " + args.get_message()); + } + + + // When the createTerms button is clicked, start by loading + // a TaxonomySession for the current context. Also get and load + // the associated term store. + function createTerms() { + session = SP.Taxonomy.TaxonomySession.getTaxonomySession(context); + termStore = session.getDefaultSiteCollectionTermStore(); + context.load(session); + context.load(termStore); + context.executeQueryAsync(onGetTaxonomySession, onFailTaxonomySession); + } + + + // This function is the success callback for loading the session and store from the createTerms function + function onGetTaxonomySession() { + // Create six GUIDs that we will need when we create a new group, term set, and associated terms + var guidGroupValue = SP.Guid.newGuid(); + var guidTermSetValue = SP.Guid.newGuid(); + var guidTerm1 = SP.Guid.newGuid(); + var guidTerm2 = SP.Guid.newGuid(); + var guidTerm3 = SP.Guid.newGuid(); + var guidTerm4 = SP.Guid.newGuid(); + + // Create a new group + var myGroup = termStore.createGroup("CustomTerms", guidGroupValue); + + // Create a new term set in the newly-created group + var myTermSet = myGroup.createTermSet("Privacy", guidTermSetValue, 1033); + + // Create four new terms in the newly-created term set + myTermSet.createTerm("Top Secret", 1033, guidTerm1); + myTermSet.createTerm("Company Confidential", 1033, guidTerm2); + myTermSet.createTerm("Partners Only", 1033, guidTerm3); + myTermSet.createTerm("Public", 1033, guidTerm4); + + // Ensure the groups variable has been set, because when this all succeeds we will + // effectively run the same code as if the user had clicked the listGroups button + groups = termStore.get_groups(); + context.load(groups); + + // Execute all the preceeding statements in this function + context.executeQueryAsync(onAddTerms, onFailAddTerms); + + } + + // If all is well with creating the terms, then this function will run. + // Effectively this runs the same code as if the user had clicked the listGroups button + // so the user will see their newly-created group + function onAddTerms() { + listGroups(); + } + + // Runs when the executeQueryAsync method in the onGetTaxonomySession function has failed. + // In this case, clear the report area in the page and tell the user what went wrong. + function onFailAddTerms(sender, args) { + $('#report').children().remove(); + $('#report').append("Failed to add terms. Error: " + args.get_message()); + } + + // Runs when the executeQueryAsync method in the createTerms function has failed. + // In this case, clear the report area in the page and tell the user what went wrong. + function onFailTaxonomySession(sender, args) { + $('#report').children().remove(); + $('#report').append("Failed to get session. Error: " + args.get_message()); + } + +}; + +//publishing.ts +// Variables used in various callbacks +JSRequest.EnsureSetup(); + +SP.SOD.execute('mquery.js', 'm$.ready', () => { + var context = SP.ClientContext.get_current(); + var web = context.get_web(); + m$('#CreatePage').click(createPage); +}); + +function createPage(evt) { + SP.SOD.execute('sp.js', 'SP.ClientConext', () => { + SP.SOD.execute('sp.publishing.js', 'SP.Publishing', () => { + var context = SP.ClientContext.get_current(); + + + var hostUrl = decodeURIComponent(JSRequest.QueryString["SPHostUrl"]); + var hostcontext = new SP.AppContextSite(context, hostUrl); + var web = hostcontext.get_web(); + var pubWeb = SP.Publishing.PublishingWeb.getPublishingWeb(context, web); + context.load(web); + context.load(pubWeb); + context.executeQueryAsync( + // Success callback after getting the host Web as a PublishingWeb. + // We now want to add a new Publishing Page. + function () { + var pageInfo = new SP.Publishing.PublishingPageInformation(); + var newPage = pubWeb.addPublishingPage(pageInfo); + context.load(newPage); + context.executeQueryAsync( + function () { + + // Success callback after adding a new Publishing Page. + // We want to get the actual list item that is represented by the Publishing Page. + var listItem = newPage.get_listItem(); + context.load(listItem); + context.executeQueryAsync( + + // Success callback after getting the actual list item that is + // represented by the Publishing Page. + // We can now get its FieldValues, one of which is its FileLeafRef value. + // We can then use that value to build the Url to the new page + // and set the href or our link to that Url. + function () { + var link = document.getElementById("linkToPage"); + link.setAttribute("href", web.get_url() + "/Pages/" + listItem.get_fieldValues().FileLeafRef); + link.innerText = "Go to new page!"; + }, + + // Failure callback after getting the actual list item that is + // represented by the Publishing Page. + function (sender, args) { + alert('Failed to get new page: ' + args.get_message()); + } + ); + }, + // Failure callback after trying to add a new Publishing Page. + function (sender, args) { + alert('Failed to Add Page: ' + args.get_message()); + } + ); + }, + // Failure callback after trying to get the host Web as a PublishingWeb. + function (sender, args) { + alert('Failed to get the PublishingWeb: ' + args.get_message()); + } + ); + }); + }); +} + +//likes +module SampleReputation { + + interface MyList extends SPClientTemplates.RenderContext_InView { + listId: string; + } + + class MyItem { + + id: number; + title: string; + likesCount: number; + isLikedByCurrentUser: boolean; + + constructor(public row: SPClientTemplates.Item) { + this.id = parseInt(row['ID']); + this.title = row['Title']; + this.likesCount = parseInt(row['LikesCount']) || 0; + this.isLikedByCurrentUser = this.getLike(row['LikedBy']); + } + + private getLike(likedBy): boolean { + if (likedBy && likedBy.length > 0) { + for (var i = 0; i < likedBy.length; i++) { + if (likedBy[i].id == _spPageContextInfo.userId) { + return true; + } + } + } + return false; + } + } + + function init() { + SP.SOD.registerSod('reputation.js', '/_layouts/15/reputation.js'); + SP.SOD.registerSod('typescripttemplates.ts', '/SPTypeScript/Extensions/typescripttemplates.js'); + SP.SOD.executeFunc('typescripttemplates.ts', 'CSR', () => { + CSR.override(10004, 1) + .onPreRender((ctx: MyList) => { + ctx.listId = ctx.listName.substring(1, 37); + }) + .header('
    ') + .body(renderTemplate) + .footer('
') + .register(); + }); + + SP.SOD.execute('mQuery.js', 'm$.ready', () => { + RegisterModuleInit('/SPTypeScript/ReputationModule/likes.js', init); + }); + + + SP.SOD.notifyScriptLoadedAndExecuteWaitingJobs('likes.js'); + } + + function renderTemplate(ctx: MyList) { + var rows = ctx.ListData.Row; + var result = ''; + for (var i = 0; i < rows.length; i++) { + var item = new MyItem(rows[i]); + result += '\ +
  • ' + item.title +'\ + \ + ' + getLikeText(item.isLikedByCurrentUser) + '' + item.likesCount + '\ + \ +
  • '; + } + return result; + } + + function getLikeText(isLikedByCurrentUser: boolean) { + return isLikedByCurrentUser ? '\u2665' : '\u2661'; + } + + export function setLike(itemId: number, listId: string): void { + var context = SP.ClientContext.get_current(); + var isLiked = m$('#likesCountText' + itemId)[0].textContent == '\u2661'; + SP.SOD.executeFunc('reputation.js', 'Microsoft.Office.Server.ReputationModel.Reputation', function () { + Microsoft.Office.Server.ReputationModel.Reputation.setLike(context, listId, itemId, isLiked); + context.executeQueryAsync( + () => { + m$('#likesCountText' + itemId)[0].textContent = getLikeText(isLiked); + var likesCount = parseInt(m$('#likesCount' + itemId)[0].textContent); + m$('#likesCount' + itemId)[0].textContent = (isLiked ? likesCount + 1 : likesCount - 1).toString(); + }, + (sender, args) => { + alert(args.get_message()); + }); + }); + } + + init(); +} + + + +//code from https://github.com/gandjustas/SharePointAngularTS +module App { + "use strict"; +var app = angular.module("app", []); +} + +// Install the angularjs.TypeScript.DefinitelyTyped NuGet package +module App { + "use strict"; + + interface Iappcontroller { + title: string; + activate: () => void; + } + + class appcontroller implements Iappcontroller { + title: string = "appcontroller"; + lists: SP.List[]; + + static $inject: string[] = ["$SharePoint", "$spnotify"]; + + constructor(private $SharePoint: App.ISharePoint, private $n:App.ISpNotify) { + this.activate(); + } + + activate() { + var loading = this.$n.showLoading(true) + this.$SharePoint + .getLists() + .then(l => this.lists = l ) + .catch((e: string) => this.$n.show(e, true)) + .finally(() => this.$n.remove(loading) ); + ; + + } + } + + angular.module("app").controller("appcontroller", appcontroller); +} + + + +module App { + "use strict"; + + export interface ISharePoint { + getLists: () => ng.IPromise; + } + + class SharePointServcie implements ISharePoint { + static $inject: string[] = ["$q"]; + + constructor(public $q: ng.IQService) { + } + + getLists() { + var promise = this.$q.defer(); + SP.SOD.executeFunc("sp.js", "SP.ClientContext", () => { + var ctx = SP.ClientContext.get_current(); + var hostUrl = decodeURIComponent(SP.ScriptHelpers.getDocumentQueryPairs()['SPHostUrl']); + var appCtx = new SP.AppContextSite(ctx, hostUrl); + var hostWeb = appCtx.get_web(); + var lists = hostWeb.get_lists(); + ctx.load(lists); + + ctx.executeQueryAsync(() => { + var result: SP.List[] = []; + for (var e = lists.getEnumerator(); e.moveNext();) { + result.push(e.get_current()); + } + promise.resolve(result); + }, + (o, args) => { promise.reject(args.get_message()); }); + }); + return promise.promise; + } + } + + angular.module("app").service("$SharePoint", SharePointServcie); +} + + +// Install the angularjs.TypeScript.DefinitelyTyped NuGet package +module App { + "use strict"; + + export interface ISpNotify { + showLoading(sticky?: boolean) : string; + show(msg: string, sticky?: boolean): string; + remove(id: string):void; + } + + class SpNotify implements ISpNotify { + static $inject: string[] = []; + + + showLoading(sticky: boolean = false) { + return SP.UI.Notify.showLoadingNotification(sticky); + } + + show(msg: string, sticky: boolean = false) { + return SP.UI.Notify.addNotification(msg, sticky); + } + + remove(id: string) { + SP.UI.Notify.removeNotification(id); + } + } + + angular.module("app").service("$spnotify", SpNotify); +} +