Если Вы забудете ввести серийный номер, то через 180 дней Вы увидите следующую картину:
"К сожалению, что-то пошло не так" и "Период пробного использования данного продукта истек". Не пугайтесь, нужно только ввести валидный ключ. Пробный, который вводили при установке, заново вбить не получится.
Что бы все вернуть на свои места - перейдите в Центр администрирования SharePoint:
Перейдите по ссылке "Преобразование типа лицензии фермы":
Введите серийный номер, нажмите "ОК":
Получили сообщение об успешной активации. Если снова вернетесь на страницу ввода серийного номера:
Как видите есть возможность снова ввести ключ. Это нужно, к примеру, для перехода со стандартной на корпоративную лицензию.
Я, как и многие, давно использую библиотеку SPServices для решения многих задач.
У этой библиотеки есть функционал по автокомплиту:
Но есть у этого механизма несколько недоработок:
нет задержки перед показом вариантов
ничего не отображается, если нет вариантов
нельзя предлагать варианты действий, если ничего не найдено
Т.е. необходимо поменять поведение, что бы варианты появлялись с задержкой в секунду, если ничего не нашли, то показываем как на картинке:
Тут же даем возможность добавить элемент:
Извещаем о добавлении:
Вот код уже поправленной функции $.fn.SPServices.SPAutocomplete:
$.fn.SPServices.SPAutocomplete = function(options) {
var opt = $.extend({}, {
webURL: "", // [Optional] The name of the Web (site) which contains the sourceList
sourceList: "", // The name of the list which contains the values
sourceColumn: "", // The static name of the column which contains the values
columnName: "", // The display name of the column in the form
CAMLQuery: "", // [Optional] For power users, this CAML fragment will be Anded with the default query on the relatedList
CAMLQueryOptions: "", // [Optional] For power users, allows specifying the CAMLQueryOptions for the GetListItems call
CAMLRowLimit: 0, // [Optional] Override the default view rowlimit and get all appropriate rows
filterType: "BeginsWith", // Type of filtering: [BeginsWith, Contains]
numChars: 0, // Wait until this number of characters has been typed before attempting any actions
ignoreCase: false, // If set to true, the function ignores case, if false it looks for an exact match
highlightClass: "", // If a class is supplied, highlight the matched characters in the values by applying that class to a wrapping span
uniqueVals: false, // If set to true, the function only adds unique values to the list (no duplicates)
maxHeight: 99999, // Sets the maximum number of values to display before scrolling occurs
slideDownSpeed: "fast", // Speed at which the div should slide down when values match (milliseconds or ["fast" | "slow"])
processingIndicator: "_layouts/images/REFRESH.GIF", // If present, show this while processing
htmlifnothingfound: "Ничего не найдено!",
debug: false // If true, show error messages;if false, run silent
}, options);
var matchNum;
// Find the input control for the column and save some of its attributes
var columnObj = $("input[Title='" + opt.columnName + "']");
columnObj.css("position", "");
var columnObjColor = columnObj.css("color");
var columnObjWidth = columnObj.css("width");
// myAdd Добавляем переменную columnObjPadding
var columnObjPadding = columnObj.css("padding");
if (columnObj.html() === null && opt.debug) {
errBox("SPServices.SPAutocomplete",
"columnName: " + opt.columnName,
"Column is not an input control or is not found on page");
return;
}
// Remove the
which isn't needed and messes up the formatting
columnObj.closest("span").find("br").remove();
columnObj.wrap("
");
// Create a div to contain the matching values and add it to the DOM
var containerId = genContainerId("SPAutocomplete", opt.columnName);
// myAdd изменен цвет на #2A8DD4 как в 2013 по умолчанию
columnObj.after("
");
// Set the width to match the width of the input control
$("#" + containerId).css("width", columnObjWidth);
// Handle keypresses
$(columnObj).keyup(function() {
// Get the column's value
var columnValue = $(this).val();
// Hide the container while we're working on it
$("#" + containerId).hide();
// Have enough characters been typed yet?
if (columnValue.length < opt.numChars) {
return false;
}
// Show the the processingIndicator as a background image in the input element
columnObj.css({
"background-image": "url(" + opt.processingIndicator + ")",
"background-position": "right",
"background-repeat": "no-repeat"
});
// Array to hold the matched values
var matchArray = [];
// Build the appropriate CAMLQuery
var camlQuery = "";
if (opt.CAMLQuery.length > 0) {
camlQuery += "";
}
camlQuery += "<" + opt.filterType + ">" + columnValue + "</" + opt.filterType + ">";
if (opt.CAMLQuery.length > 0) {
camlQuery += opt.CAMLQuery + "";
}
camlQuery += "";
// Call GetListItems to find all of the potential values
$().SPServices({
operation: "GetListItems",
async: false,
webURL: opt.WebURL,
listName: opt.sourceList,
CAMLQuery: camlQuery,
CAMLQueryOptions: opt.CAMLQueryOptions,
CAMLViewFields: "",
CAMLRowLimit: opt.CAMLRowLimit,
completefunc: function(xData) {
// Handle upper/lower case if ignoreCase = true
var testValue = opt.ignoreCase ? columnValue.toUpperCase() : columnValue;
// See which values match and add the ones that do to matchArray
$(xData.responseXML).SPFilterNode("z:row").each(function() {
var thisValue = $(this).attr("ows_" + opt.sourceColumn);
var thisValueTest = opt.ignoreCase ? $(this).attr("ows_" + opt.sourceColumn).toUpperCase() : $(this).attr("ows_" + opt.sourceColumn);
// Make sure we have a match...
if (opt.filterType === "Contains") {
var firstMatch = thisValueTest.indexOf(testValue);
if ((firstMatch >= 0) &&
// ...and that the match is not already in the array if we want uniqueness
(!opt.uniqueVals || ($.inArray(thisValue, matchArray) === -1))) {
matchArray.push($(this).attr("ows_" + opt.sourceColumn));
}
} else {
// Handles normal case, which is BeginsWith and and other unknown values
if (testValue === thisValueTest.substr(0, testValue.length) &&
// ...and that the match is not already in the array if we want uniqueness
(!opt.uniqueVals || ($.inArray(thisValue, matchArray) === -1))) {
matchArray.push($(this).attr("ows_" + opt.sourceColumn));
}
}
});
}
});
// Build out the set of list elements to contain the available values
var out = "";
// !myAdd
if(matchArray.length==0){
matchArray.push(opt.htmlifnothingfound);
}
for (i = 0; i < matchArray.length; i++) {
// If a highlightClass has been supplied, wrap a span around each match
if (opt.highlightClass.length > 0) {
// Set up Regex based on whether we want to ignore case
var thisRegex = new RegExp(columnValue, opt.ignoreCase ? "gi" : "g");
// Look for all occurrences
var matches = matchArray[i].match(thisRegex);
var startLoc = 0;
// Loop for each occurrence, wrapping each in a span with the highlightClass CSS class
for (matchNum = 0; matchNum < matches.length; matchNum++) {
var thisPos = matchArray[i].indexOf(matches[matchNum], startLoc);
var endPos = thisPos + matches[matchNum].length;
var thisSpan = "" + matches[matchNum] + "";
matchArray[i] = matchArray[i].substr(0, thisPos) + thisSpan + matchArray[i].substr(endPos);
startLoc = thisPos + thisSpan.length;
}
}
// Add the value to the markup for the container
out += "
" + matchArray[i] + "
";
}
// Add all the list elements to the containerId container
$("#" + containerId).html(out);
// Set up hehavior for the available values in the list element
// !myAdd if(matchArray[0] != opt.htmlifnothingfound)
if(matchArray[0] != opt.htmlifnothingfound){
$("#" + containerId + " li").click(function() {
$("#" + containerId).fadeOut(opt.slideUpSpeed);
columnObj.val($(this).text());
}).mouseover(function() {
var mouseoverCss = {
"cursor": "hand",
"color": "#ffffff",
"background": "#3399ff"
};
$(this).css(mouseoverCss);
}).mouseout(function() {
var mouseoutCss = {
"cursor": "inherit",
"color": columnObjColor,
"background": "transparent"
};
$(this).css(mouseoutCss);
});}
// If we've got some values to show, then show 'em!
if (matchArray.length > 0) {
// !myAdd delay(1000)
$("#" + containerId).slideDown(opt.slideDownSpeed).delay(2000);
}
// Remove the processing indicator
columnObj.css("background-image", "");
});
};
Просто замените код из библиотеки SPServices кодом выше.
Правда теперь и прикреплять автокомплит надо несколько иначе:
function AddAutoCompleteContractor() {
console.log("Начало выполнения функции 'AddAutoCompleteContractor()");
//Добавляем autocomplete для поля "Наименование контрагента"
$().SPServices.SPAutocomplete({
sourceList: "Contractors",
sourceColumn: "Title",
columnName: "Наименование контрагента",
ignoreCase: true,
filterType: "Contains",
numChars: 3,
slideDownSpeed: 400,
htmlifnothingfound: "Ничего не найдено! <a href='#' onClick='ShowPopupContractor()'>Добавить?</a>",
debug: true
});
}
Добавили опцию "htmlifnothingfound" - в ней указывайте html, который будет отображаться, если ничего не найдено.
Так же был изменен цвет, под 2013 и ширину, что бы вровень было. В 2013 padding появился.
Теперь нам необходимо добавить код, который покажет popup:
function ShowPopupContractor() {
console.log("Начало выполнения функции 'ShowPopupContractor()");
$("#Anchor").append("Добавьте контрагента:
");
$('#popupDivContractor').show();
SP.UI.ModalDialog.showModalDialog({
html: document.getElementById('popupDivContractor'),
title: "Введите комментарий",
allowMaximize: false,
showClose: false,
autoSize: true,
dialogReturnValueCallback: onPopUpCloseCallBackContractor
});
}
Дальше добавим функцию добавление элемента списка и колбэки, которые отработают при удачном\неудачном завершении процесса создания элемента:
function createListItemContractor() {
console.log("Начало выполнения функции 'createListItemContractor()");
var clientContext = new SP.ClientContext(currentWebUrl);
var oList = clientContext.get_web().get_lists().getByTitle('Contractors');
var itemCreateInfo = new SP.ListItemCreationInformation();
this.oListItem = oList.addItem(itemCreateInfo);
oListItem.set_item('Title', $("#ContractorInput").val());
oListItem.update();
clientContext.load(oListItem);
clientContext.executeQueryAsync(
Function.createDelegate(this, this.onQuerySucceededСreateListItemContractor),
Function.createDelegate(this, this.onQueryFailedСreateListItemContractor)
);
}
function onQuerySucceededСreateListItemContractor() {
console.log("Начало выполнения функции 'onQuerySucceededСreateListItemContractor()");
console.log('Элемент создан: ' + oListItem.get_id());
}
function onQueryFailedСreateListItemContractor(sender, args) {
console.log("Начало выполнения функции 'onQueryFailedСreateListItemContractor()");
console.log('Ошибка при создании элемента. ' + args.get_message() + '\n' + args.get_stackTrace());
}
Теперь добавим функции, которые закрепим за кнопкой Добавить и Отмена.
При добавлении будет создавать элемент и закрытие формы, в случае нажатия по кнопке Отмена - только закрытие формы. Важно отметить, что в этих функциях мы сообщаем и результат для колбэка закрытия формы. Именно в колбэке логика по которой мы показываем уведомление.
function onPopUpCloseCallBackContractor(result, returnValue) {
console.log("Начало выполнения функции 'onPopUpCloseCallBackContractor()");
$("nobr:contains('Наименование контрагента')").closest('tr').find("input").val("");
$("nobr:contains('Наименование контрагента')").closest('tr').find("input").keyup()
if (result == SP.UI.DialogResult.OK) {
SP.UI.Status.removeAllStatus(true);
var sId = SP.UI.Status.addStatus("Контрагент добавлен!");
SP.UI.Status.setStatusPriColor(sId, 'green');
}
else if (result == SP.UI.DialogResult.cancel) {
SP.UI.Status.removeAllStatus(true);
var sId = SP.UI.Status.addStatus("Вы не стали добавлять контрагента");
SP.UI.Status.setStatusPriColor(sId, 'yellow');
}
}
function closePopupOkContractor() {
console.log("Начало выполнения функции 'closePopupOkContractor()");
createListItemContractor();
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.OK, null);
}
function closePopupCancelContractor() {
console.log("Начало выполнения функции 'closePopupCancelContractor()");
SP.UI.ModalDialog.commonModalDialogClose(SP.UI.DialogResult.cancel, null);
}
После старта рабочего процесса из формы элемента - Вас вернет на представление списка.
Поменять такое поведение можно, если добавить немного JavaScript кода на страницу с представлением списка. Код будет читать referrer, брать ID и делать редирект на форму элемента списка. В нашем случае на форму просмотра. При это важно, что бы код отработал только если Вы перешли на страницу после старта рабочего процесса. Это мы сможем понять по присутствию "Workflow.aspx" в referrer.
Код выглядит так:
// Функция позволяет взять параметр из referrer
function getParameterByName(name, url) {
name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
results = regex.exec(url);
return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}
// Получаем referrer
var ref = document.referrer
// Получаем ID из referrer
var ID = getParameterByName("ID", ref)
if (ref.indexOf("Workflow.aspx") > -1){
// Делаем редирект
window.location = "/office/Lists/Contractors/DispForm.aspx?ID=" + ID
}
Теперь надо добавить это все в представление списка, воспользуемся SharePoint Designer 2013:
В моем случая я имею только одно представление, откроем его в расширенном режиме и добавим код, как на картинке: