О бедной XWiki замолвите слово

Пролог.

"Ежели Вы вежливы,
То говорите: "Здрасти".
А ежли Вам ответят: "Нет",
Сдерживайте страсти!" (с)

Однажды… когда в очередной раз, выполняя рутинную работу, Ты будешь, теряя время, вспоминать: в каком из вариантов проекта и по какой причине были внесены изменения в расчеты, оформление или текст… о Пользователь — знай, что для тебя настало время борьбы со Страстями за Структурирование! Структурирование, или стратегия организации разрозненной информации, упирается в возможности и способности конкретного человека, продуктивность которого всецело зависит от тех инструментов которыми он пользуется для этих целей, будь то блокнот или АСУ.

На сегодняшний день существует огромное количество таких инструментов прямо и косвенных решающих эту задачу, с разной степенью эффективности, но на мой взгляд будущее за продуктами интегрирующие в себя не только инструменты ввода, сортировки, представления и оформления данных, но так же содержащие инструменты аналитики, программирования и поиска. XWiki, как представителю такого направления и будет посвящена сея статья, которая будет включать в себя обзор, установку и настройку Вики-движка, которая будет интересная как новичкам, так и продвинутым пользователям.

Добро пожаловать под Cut (осторожно — трафик, картинки)

Экспозиция

О Вики-движке XWiki в русскоязычном сегменте Интернета почти ничего нет, кроме общей информации и парочки руководств, что на мой взгляд категорически неверно, ибо это замечательный инструмент и помощник, со своими плюсами и минусами, конечно. XWiki — это Вики-движок второго поколения, который характеризуются возможностью структуризации информации и программного доступа к базе вики. Написан на языке Java, лицензия распространения LGPL, функциональность включает в себя блог, инструменты API, комментарии, аутентификацию по LDAP, экспорт страниц в PDF. Используется многими компаниями по всему миру. 25 языков интерфейса, включая русский. Так же более подробно желающие могут сравнить на wikimatrix с наиболее распространенными в Рунете Вики-движками: DokuWiki и MediaWiki.

Завязка

Скачать последнюю, на момент написания статьи, версию XWiki 7.1.2 можно по следующей ссылке: http://enterprise.xwiki.org/xwiki/bin/view/Main/Download

Варианты установки поддерживают: Windows, Debian, веб-контейнер (веб-сервер) — *.war, мультисистемный формат — *.jar и портативную версию вики на базе связки Jetty+HSQLDB, которая, ИМХО, наиболее удобна для настройки/эксплуатации Пользователем как в Windows, так и в Linux. О ней и пойдет речь.

Для того чтобы установить Xwiki, необходимо чтобы в системе была установлена Java, а так же распаковать файлы из архива ZIP в корень диска (также рекомендуется переименовать папку до более короткого пути, например так: "D:\xwiki-7.1.2"). Запуск осуществляется файлом start_xwiki.bat, в котором уже прописаны все необходимые настройки.

01. окно консоли

Теперь нам необходимо открыть окно web-браузера (окно консоли при этом закрывать категорически не рекомендуется), и ввести указанный URL из консоли, в нашем случае это: panther.itme.info:8080/xwiki/bin/view/Main/

Здесь так же стоит добавить, что порт по умолчанию, с которого стартует XWiki — 8080, если по тем или иным причинам он у вас занят, то его можно изменить, отредактировав через Блокнот start_xwiki.bat.

После загрузки в браузере откроется следующее окно:

02. Первый запуск. Общее окно

Из интересного здесь ссылка на гайд на английском — Documentation, но нас будет интересовать совершенно другое, а именно кликаем в правом верхнем углу на Log-in и вводим для входа в админку:

Login:        Admin
Password: admin

Здесь стоит отметить, что в этом месте регистр имеет значение!

03. Редактирование гаджетов

Здесь хочу остановиться на следующем:
1. Боковые панели приобрела дополнительный функционал, который настраивается Пользователем.
2. Функционал в XWiki позволяет на страницах редактировать не только текст, с помощью обычного или WYSIWYG редактора, выводя его в колонки с помощью редактирования Inline form, но и вставлять гаджеты на страницу. Под гаджетом в XWiki понимается выводимый в некоторой области Макрос, т.е. вызов одной или последовательности команд, в частности это может быть ссылка на другую страницу или даже ленту блога, облако тэгов, формы для отправки сообщений и т.д. и т.п.

Макросы в XWiki по сути являются основой данного движка, именно благодаря им Пользователь может настроить практически все, будь то: свое мини-приложение, внешний вид страниц и панелей или интеграция собственного расширения (плагина).

Развитие

Здесь нужно немного отвлечься и рассказать об организационной структуре XWiki, а именно о жизненном цикле вики-страниц. Здесь есть одна тонкость, а именно: Пользователь может создавать Page и Space, и если с Page'ами все более или менее понятно, то при создании Space создается Заголовок области, внутри которого будет создано автоматом Page с именем WebHome, но при этом выводится будет всюду Заголовок области, а адресация будет на WebHome, что может создать некоторые трудности при ссылке на страницу. При этом нет ограничений по уровню вложения, которые можно делать как к Space, так и к Page.

Макросы.

Для начала необходимо выбрать страницу для редактирования и войти в редактор.



Затем необходимо набрать либо в текстовом режиме сам макрос, вместе с параметрами, либо, воспользовавшись графическим интерфейсом выбрать необходимый макрос из списка.




и заполнить необходимые поля:



Но это все была лирика, давайте перейдем к практике и начнем мы с настройки интерфейса. Для этого необходимо кликнуть на левой панели на пиктограмму Panels и в открывшейся странице запустить Panel Wizard. Перед нами предстанет интерфейс настроек администратора, открытый во вкладке Panel Wizard. альтернативный и основной способ перейти к настройкам XWiki — это клик по стрелочке в верхнем выпадающем списке рядом с Home и выбор пункта Administer Wiki.

04. настройка панелей

Вкладка на странице настроек панели Page Layout позволяет настроить расположение, число и ширину колонок нашей вики. Соседствующая рядом вкладка Panel List включает в себя приложения (макросы), которое может быть расположено на наших полях, при этом они включают в себя окошко предпросмотра, а так же управляющие элементы включения/исключения и редактирования содержимого и функций. Предпросмотр для соответствующих приложений, находящихся в виде кнопок и функционала на полях, выключен. Для того что бы настроить функционал приложения — необходимо кликнуть на Edit, что бы удалить макрос — кликнуть на Delete, что бы убрать/поместить на панель приложение/функционал — перетащить используя метод Drag and Drop.

Теперь мы сделаем правую панель навигационной, для этого убираем с правой панели Quick Links и My Recent Modifications и добавляем Tag Cloud, Navigation и Create Page, кликаем на Save the new Layout при этом заходим в правку Navigation и вставляем следующий код, который сделает наш серфинг более удобным:

код для Content
{{velocity}}
#panelheader($services.localization.render('xe.panels.navigation'))
## Escape special characters in macro parameter values.
#set ($openToDoc = $doc.documentReference.toString().replaceAll('([~"])', '~$1'))
{{documentTree showSpaces="false" showWikis="true" showTranslations="false" showAttachments="true"
showChildDocuments="true" compact="true" openTo="document:$openToDoc" /}}
#panelfooter()
{{/velocity}}



Что нам это дает? Это дает отображение древовидную структуру для навигации между вложениями, Pages и Spaces, без вывода дополнительной отвлекающей информации. Теперь настало самое внести вдохнуть краски в наш новый сайт и уйти от плоского интерфейса. Для этого выбираем в меню LOOK & FEEL пункт Presentation. Здесь мы меняем Icon Theme на Silk и Color Theme на Garden.

Вуаля.

05. внешний вид

Теперь пора подумать и о медиа инструментах, а именно — какой же блог без галереи и графики? К сожалению встроенной галереи XWiki не имеет, а потому придется потрудиться что бы установить и настроить дополнение (Extensions), для этого заходим в меню EXTENSION MANAGER пункт Add Extensions. Здесь можно из веб репозитория установить необходимые дополнения, в данном случае нас будет интересовать плагин Lightbox Macro, с помощью которого удобно организовывать слайд шоу, а так же объединять по группам картинки. Для установки вводим в строку поиска слово lightbox и в полученном результате поиска кликаем install.

06. установка макроса



Теперь переходим на главную страницу нашей XWiki и здесь в панели Navigation мы обнаружим 2 новых Space Lightbox и LightboxMacro. Значит наступило самое время применить макрос в дело, для этого создаем тестовый Space под именем Test page и во вкладке Attachments загружаем картинки для тестирования галереи, в нашем случае это будут фотографии со дня празднования 9го мая 2014 года снятые на ничем не примечательный китайфон на Андроиде Jiayu G3.

Код для галереи
{{velocity}}
#set($myArray=$doc.AttachmentList)
#set($myArray=$sorttool.sort($myArray, 'filename'))
#foreach ($item in $myArray)#if($item.isImage()){{lightbox image=$item.filename title="Hello" width="20%" group="d1" height="20%"/}}#end#end
{{/velocity}}



Текст кода интерпретируется следующим образом: в массив $myArray закладывается список вложений на странице, затем производится сортировка по имени (для тех случаев если загруженные файлы с камеры были загружены в разнобой, но в то же время хранят в имени файла дату и время съемки, или хотя бы нумерации очередности снимков). После чего для каждого вложения, если оно есть изображение, выводится миниатюра высотой 20% от оригинала. Здесь так же нужно сказать, что параметры макроса включают в себя следующие пункты:

Param Description
image(required) An url or the attached image file. For example, "cat.jpg" or "xwiki:Space.Page@cat.jpg" or "www.google.com/logos/wateronmoon09-hp.gif"
title A short description
width The width of the image.
height The height of the image.
group A string that identify it as a member of a group. A group of images can be viewed as a series of slides.
07. Превью галереи

Чем удобен этот макрос? Тем, что автоматизирует процесс вывода вложений вне зависимости от того сколько, каких изображений и под каким именем были загружены. Так же можно кликнуть на любую из миниатюр и во всплывающем окне будет выведено понравившееся фото, что так же является несомненным плюсом. Но ложечкой дегтя в данном случае будет тот факт, что во всплывающем окне изображение будет открыто в оригинальном размере, что не всегда удобно, особенно, если это разрешение превышает рабочее разрешение экрана монитора. В таком случае делаем следующее:
1. Переходим по ссылке на страницу макроса Lightbox;
2. Кликаем на стрелочке меню Edit и в раскрывшемся списке выпадающего меню выбираем Objects;
3. В новом окне переходим к коду развернув списки Objects of type XWiki.JavaScriptExtension (1) и Objects of type XWiki.StyleSheetExtension (1);
4. Теперь в код JS вносим следующие изменения:

изменения в код JS
+ resizeSpeed: 10, // controls the speed of the image resizing animations (1=slowest and 10=fastest)
...
+ var maxheight = 640;
+ if(imgPreloader.height > maxheight)
+ {
+ var scale = imgPreloader.height/maxheight
+ imgPreloader.height = maxheight;
+ imgPreloader.width = imgPreloader.width/scale;
+ }



Код целиком с учетом исправлений
//----------------------------------------------------------------------------
//
// Lightbox v2.04
// by Lokesh Dhakar - http://www.lokeshdhakar.com
//
// Licensed under the Creative Commons Attribution 2.5 License - http://creativecommons.org/licenses/by/2.5/
//  - Free for use in both personal and commercial projects
// - Attribution requires leaving author name, author link, and the license info intact.
//
// Cleaned up using jslint.
//----------------------------------------------------------------------------------
/*global LightboxOptions, Lightbox, Builder, Class, Prototype, $, $$, $w , Effect*/
LightboxOptions = Object.extend({
fileLoadingImage:        '$doc.getAttachmentURL("loading.gif")',
fileBottomNavCloseImage: '$doc.getAttachmentURL("closelabel.gif")',
overlayOpacity: 0.8,   // controls transparency of shadow overlay
animate: true,         // toggles resizing animations
resizeSpeed: 10,        // controls the speed of the image resizing animations (1=slowest and 10=fastest)
borderSize: 10,         //if you adjust the padding in the CSS, you will need to update this variable
// When grouping images this is used to write: Image # of #.
// Change it for non-english localization
labelImage: "Image",
labelOf: "of"
}, window.LightboxOptions || {});
// -----------------------------------------------------------------------------------
var Lightbox = Class.create();
Lightbox.prototype = {
imageArray: [],
activeImage: undefined,
// initialize()
// Constructor runs on completion of the DOM loading. Calls updateImageList and then
// the function inserts html at the bottom of the page which is used to display the shadow
// overlay and the image container.
//
initialize: function () {
this.updateImageList();
this.keyboardAction = this.keyboardAction.bindAsEventListener(this);
if (LightboxOptions.resizeSpeed > 10) {
LightboxOptions.resizeSpeed = 10;
}
if (LightboxOptions.resizeSpeed < 1)  {
LightboxOptions.resizeSpeed = 1;
}
this.resizeDuration = LightboxOptions.animate ? ((11 - LightboxOptions.resizeSpeed) * 0.15) : 0;
this.overlayDuration = LightboxOptions.animate ? 0.2 : 0;  // shadow fade in/out duration
// When Lightbox starts it will resize itself from 250 by 250 to the current image dimension.
// If animations are turned off, it will be hidden as to prevent a flicker of a
// white 250 by 250 box.
var size = (LightboxOptions.animate ? 250 : 1) + 'px';
// Code inserts html at the bottom of the page that looks similar to this:
//
//  <div id="overlay"></div>
//  <div id="lightbox">
//      <div id="outerImageContainer">
//          <div id="imageContainer">
//              <img id="lightboxImage">
//              <div style="" id="hoverNav">
//                  <a href="#" id="prevLink"></a>
//                  <a href="#" id="nextLink"></a>
//              </div>
//              <div id="loading">
//                  <a href="#" id="loadingLink">
//                      <img src="images/loading.gif">
//                  </a>
//              </div>
//          </div>
//      </div>
//      <div id="imageDataContainer">
//          <div id="imageData">
//              <div id="imageDetails">
//                  <span id="caption"></span>
//                  <span id="numberDisplay"></span>
//              </div>
//              <div id="bottomNav">
//                  <a href="#" id="bottomNavClose">
//                      <img src="images/close.gif">
//                  </a>
//              </div>
//          </div>
//      </div>
//  </div>
var objBody = $$('body')[0];
objBody.appendChild(Builder.node('div', {id: 'overlay'}));
objBody.appendChild(Builder.node('div', {id: 'lightbox'}, [
  Builder.node('div', {id: 'outerImageContainer'},
      Builder.node('div', {id: 'imageContainer'}, [
          Builder.node('img', {id: 'lightboxImage'}),
          Builder.node('div', {id: 'hoverNav'}, [
              Builder.node('a', {id: 'prevLink', href: '#' }),
              Builder.node('a', {id: 'nextLink', href: '#' })
          ]),
          Builder.node('div', {id: 'loading'},
              Builder.node('a', {id: 'loadingLink', href: '#' },
                  Builder.node('img', {src: LightboxOptions.fileLoadingImage})
              )
          )
      ])
  ),
  Builder.node('div', {id: 'imageDataContainer'},
      Builder.node('div', {id: 'imageData'}, [
          Builder.node('div', {id: 'imageDetails'}, [
              Builder.node('span', {id: 'caption'}),
              Builder.node('span', {id: 'numberDisplay'})
          ]),
          Builder.node('div', {id: 'bottomNav'},
              Builder.node('a', {id: 'bottomNavClose', href: '#' },
                  Builder.node('img', { src: LightboxOptions.fileBottomNavCloseImage })
              )
          )
      ])
  )
]));
$('overlay').hide().observe('click', (function () {
this.end();
}).bind(this));
$('lightbox').hide().observe('click', (function (event) {
if (event.element().id == 'lightbox') {
this.end();
}
}).bind(this));
$('outerImageContainer').setStyle({ width: size, height: size });
$('prevLink').observe('click', (function (event) {
event.stop();
this.changeImage(this.activeImage - 1);
}).bindAsEventListener(this));
$('nextLink').observe('click', (function (event) {
event.stop();
this.changeImage(this.activeImage + 1);
}).bindAsEventListener(this));
$('loadingLink').observe('click', (function (event) {
event.stop();
this.end();
}).bind(this));
$('bottomNavClose').observe('click', (function (event) {
event.stop();
this.end();
}).bind(this));
var th = this;
(function () {
  var ids =
      'overlay lightbox outerImageContainer imageContainer lightboxImage hoverNav prevLink nextLink loading loadingLink ' +
      'imageDataContainer imageData imageDetails caption numberDisplay bottomNav bottomNavClose';
  $w(ids).each(function (id) {
th[id] = $(id);
});
}).defer();
},
//
// updateImageList()
// Loops through anchor tags looking for 'lightbox' references and applies onclick
// events to appropriate links. You can rerun after dynamically adding images w/ajax.
//
updateImageList: function () {
this.updateImageList = Prototype.emptyFunction;
document.observe('click', (function (event) {
  var target = event.findElement('a[rel^=lightbox]') || event.findElement('area[rel^=lightbox]');
  if (target) {
      event.stop();
      this.start(target);
  }
}).bind(this));
},
//
//  start()
//  Display overlay and lightbox. If image is part of a set, add siblings to imageArray.
//
start: function (imageLink) {
$$('select', 'object', 'embed').each(function (node) {
node.style.visibility = 'hidden';
});
// stretch overlay to fill page and fade in
var arrayPageSize = this.getPageSize();
$('overlay').setStyle({ width: arrayPageSize[0] + 'px', height: arrayPageSize[1] + 'px' });
var effect = new Effect.Appear(this.overlay, { duration: this.overlayDuration, from: 0.0, to: LightboxOptions.overlayOpacity });
this.imageArray = [];
var imageNum = 0;
if ((imageLink.rel == 'lightbox')) {
  // if image is NOT part of a set, add single image to imageArray
  this.imageArray.push([imageLink.href, imageLink.title]);
} else {
  // if image is part of a set..
  this.imageArray =
      $$(imageLink.tagName + '[href][rel="' + imageLink.rel + '"]').
      collect(function (anchor) {
return [anchor.href, anchor.title];
}).
      uniq();
  while (this.imageArray[imageNum][0] != imageLink.href) {
imageNum++;
}
}
// calculate top and left offset for the lightbox
var arrayPageScroll = document.viewport.getScrollOffsets();
var lightboxTop = arrayPageScroll[1] + (document.viewport.getHeight() / 10);
var lightboxLeft = arrayPageScroll[0];
this.lightbox.setStyle({ top: lightboxTop + 'px', left: lightboxLeft + 'px' }).show();
this.changeImage(imageNum);
},
//
//  changeImage()
//  Hide most elements and preload image in preparation for resizing image container.
//
changeImage: function (imageNum) {
this.activeImage = imageNum; // update global var
// hide elements during transition
if (LightboxOptions.animate) {
this.loading.show();
}
this.lightboxImage.hide();
this.hoverNav.hide();
this.prevLink.hide();
this.nextLink.hide();
// HACK: Opera9 does not currently support scriptaculous opacity and appear fx
this.imageDataContainer.setStyle({opacity: 0.0001});
this.numberDisplay.hide();
var imgPreloader = new Image();
// once image is preloaded, resize image container
imgPreloader.onload = (function () {
  var maxheight = 640;
  if(imgPreloader.height > maxheight)
    {
    var scale = imgPreloader.height/maxheight
    imgPreloader.height = maxheight;
    imgPreloader.width = imgPreloader.width/scale;
     }
       
  this.lightboxImage.src = this.imageArray[this.activeImage][0];
  this.resizeImageContainer(imgPreloader.width, imgPreloader.height);
}).bind(this);
imgPreloader.src = this.imageArray[this.activeImage][0];
},
//
//  resizeImageContainer()
//
resizeImageContainer: function (imgWidth, imgHeight) {
// get current width and height
var widthCurrent  = this.outerImageContainer.getWidth();
var heightCurrent = this.outerImageContainer.getHeight();
// get new width and height
var widthNew  = (imgWidth  + LightboxOptions.borderSize * 2);
var heightNew = (imgHeight + LightboxOptions.borderSize * 2);
// scalars based on change from old to new
var xScale = (widthNew  / widthCurrent)  * 100;
var yScale = (heightNew / heightCurrent) * 100;
// calculate size difference between new and old image, and resize if necessary
var wDiff = widthCurrent - widthNew;
var hDiff = heightCurrent - heightNew;
if (hDiff != 0) {
var scaleXEffect = new Effect.Scale(this.outerImageContainer, yScale, {scaleX: false, duration: this.resizeDuration, queue: 'front'});
}
if (wDiff != 0) {
var scaleYEffect = new Effect.Scale(this.outerImageContainer, xScale, {scaleY: false, duration: this.resizeDuration, delay: this.resizeDuration});
}
// if new and old image are same size and no scaling transition is necessary,
// do a quick pause to prevent image flicker.
var timeout = 0;
if ((hDiff == 0) && (wDiff == 0)) {
  timeout = 100;
  if (Prototype.Browser.IE) {
timeout = 250;
}
}
(function () {
  this.prevLink.setStyle({ height: imgHeight + 'px' });
  this.nextLink.setStyle({ height: imgHeight + 'px' });
  this.imageDataContainer.setStyle({ width: widthNew + 'px' });
  this.showImage();
}).bind(this).delay(timeout / 1000);
},
//
//  showImage()
//  Display image and begin preloading neighbors.
//
showImage: function () {
this.loading.hide();
var effectAppear = new Effect.Appear(this.lightboxImage, {
  duration: this.resizeDuration,
  queue: 'end',
  afterFinish: (function () {
this.updateDetails();
}).bind(this)
});
this.preloadNeighborImages();
},
//
//  updateDetails()
//  Display caption, image number, and bottom nav.
//
updateDetails: function () {
// if caption is not null
if (this.imageArray[this.activeImage][1] != "") {
  this.caption.update(this.imageArray[this.activeImage][1]).show();
}
// if image is part of set display 'Image x of x'
if (this.imageArray.length > 1) {
  this.numberDisplay.update(LightboxOptions.labelImage + ' ' + (this.activeImage + 1) + ' ' + LightboxOptions.labelOf + '  ' + this.imageArray.length).show();
}
var effectParallel = new Effect.Parallel(
  [
new Effect.SlideDown(this.imageDataContainer, { sync: true, duration: this.resizeDuration, from: 0.0, to: 1.0 }),
      new Effect.Appear(this.imageDataContainer, { sync: true, duration: this.resizeDuration })
  ],
  {
      duration: this.resizeDuration,
      afterFinish: (function () {
     // update overlay size and update nav
     var arrayPageSize = this.getPageSize();
     this.overlay.setStyle({ height: arrayPageSize[1] + 'px' });
     this.updateNav();
      }).bind(this)
  }
);
},
//
//  updateNav()
//  Display appropriate previous and next hover navigation.
//
updateNav: function () {
this.hoverNav.show();      
// if not first image in set, display prev image button
if (this.activeImage > 0) {
this.prevLink.show();
}
// if not last image in set, display next image button
if (this.activeImage < (this.imageArray.length - 1)) {
this.nextLink.show();
}
this.enableKeyboardNav();
},
//
//  enableKeyboardNav()
//
enableKeyboardNav: function () {
document.observe('keydown', this.keyboardAction);
},
//
//  disableKeyboardNav()
//
disableKeyboardNav: function () {
document.stopObserving('keydown', this.keyboardAction);
},
//
//  keyboardAction()
//
keyboardAction: function (event) {
var keycode = event.keyCode;
var escapeKey;
if (event.DOM_VK_ESCAPE) {  // mozilla
  escapeKey = event.DOM_VK_ESCAPE;
} else { // ie
  escapeKey = 27;
}
var key = String.fromCharCode(keycode).toLowerCase();
if (key.match(/x|o|c/) || (keycode == escapeKey)) { // close lightbox
  this.end();
} else if ((key == 'p') || (keycode == 37)) { // display previous image
  if (this.activeImage != 0){
      this.disableKeyboardNav();
      this.changeImage(this.activeImage - 1);
  }
} else if ((key == 'n') || (keycode == 39)) { // display next image
  if (this.activeImage != (this.imageArray.length - 1)) {
      this.disableKeyboardNav();
      this.changeImage(this.activeImage + 1);
  }
}
},
//
//  preloadNeighborImages()
//  Preload previous and next images.
//
preloadNeighborImages: function () {
var preloadNextImage, preloadPrevImage;
if (this.imageArray.length > this.activeImage + 1) {
  preloadNextImage = new Image();
  preloadNextImage.src = this.imageArray[this.activeImage + 1][0];
}
if (this.activeImage > 0) {
  preloadPrevImage = new Image();
  preloadPrevImage.src = this.imageArray[this.activeImage - 1][0];
}
},
//
//  end()
//
end: function () {
this.disableKeyboardNav();
this.lightbox.hide();
var effectFade = new Effect.Fade(this.overlay, { duration: this.overlayDuration });
$$('select', 'object', 'embed').each(function (node) {
node.style.visibility = 'visible';
});
},
//
//  getPageSize()
//
getPageSize: function () {
var xScroll, yScroll, pageHeight, pageWidth, windowWidth, windowHeight;
if (window.innerHeight && window.scrollMaxY) { 
xScroll = window.innerWidth + window.scrollMaxX;
yScroll = window.innerHeight + window.scrollMaxY;
} else if (document.body.scrollHeight > document.body.offsetHeight) { // all but Explorer Mac
xScroll = document.body.scrollWidth;
yScroll = document.body.scrollHeight;
} else { // Explorer Mac...would also work in Explorer 6 Strict, Mozilla and Safari
xScroll = document.body.offsetWidth;
yScroll = document.body.offsetHeight;
}
if (self.innerHeight) { // all except Explorer
if (document.documentElement.clientWidth) {
windowWidth = document.documentElement.clientWidth;
} else {
windowWidth = self.innerWidth;
}
windowHeight = self.innerHeight;
} else if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
windowWidth = document.documentElement.clientWidth;
windowHeight = document.documentElement.clientHeight;
} else if (document.body) { // other Explorers
windowWidth = document.body.clientWidth;
windowHeight = document.body.clientHeight;
} 
// for small pages with total height less then height of the viewport
if (yScroll < windowHeight) {
pageHeight = windowHeight;
} else {
pageHeight = yScroll;
}
// for small pages with total width less then width of the viewport
if (xScroll < windowWidth) { 
pageWidth = xScroll; 
} else {
pageWidth = windowWidth;
}
return [pageWidth, pageHeight];
}
};
document.observe('dom:loaded', function () {
var lightbox = new Lightbox();
});




Теперь правим Objects of type XWiki.StyleSheetExtension (1)

Изменения в XWiki.Style
меняем
-#lightbox{ position: absolute; left: 0; width: 100%; z-index: 1001; text-align: center; line-height: 0;}#lightbox img{ width: auto; height: auto;}#lightbox a img{ border: none; }

на

+#lightbox{ position: absolute; left: 0; width: 100%; z-index: 1001; text-align: center; line-height: 0;}#lightbox img{ max-height: 640px;}#lightbox a img{ border: none; }


Итоговый XWiki.Style
#lightbox{
position: absolute;
left: 0;
width: 100%;
z-index: 1001;
text-align: center;
line-height: 0;
}
#lightbox img{ max-height: 640px;}
#lightbox a img{ border: none; }
#outerImageContainer{
position: relative;
background-color: #fff;
width: 250px;
height: 250px;
margin: 0 auto;
}
#imageContainer{
padding: 10px;
}
#loading{
position: absolute;
top: 40%;
left: 0%;
height: 25%;
width: 100%;
text-align: center;
line-height: 0;
}
#hoverNav{
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
z-index: 10;
}
#imageContainer>#hoverNav{
left: 0;
}
#hoverNav a{
outline: none;
}
#prevLink, #nextLink{
width: 49%;
height: 100%;
background-image: url(data:image/gif;base64,AAAA); /* Trick IE into showing hover */
display: block;
}
#prevLink {
left: 0;
float: left;
}
#nextLink {
right: 0;
float: right;
}
#prevLink:hover, #prevLink:visited:hover {
background: url($doc.getAttachmentURL(«prevlabel.gif»)) left 15% no-repeat;
}
#nextLink:hover, #nextLink:visited:hover {
background: url($doc.getAttachmentURL(«nextlabel.gif»)) right 15% no-repeat;
}
#imageDataContainer{
font: 10px Verdana, Helvetica, sans-serif;
background-color: #fff;
margin: 0 auto;
line-height: 1.4em;
overflow: auto;
width: 100%;
}
#imageData{
padding:0 10px;
color: #666;
}
#imageData #imageDetails{
width: 70%;
float: left;
text-align: left;
}
#imageData #caption{
font-weight: bold;
}
#imageData #numberDisplay{
display: block;
clear: left;
padding-bottom: 1.0em;
}
#imageData #bottomNavClose{
width: 66px;
float: right;
padding-bottom: 0.7em;
outline: none;
}
#overlay{
position: absolute;
top: 0;
left: 0;
z-index: 90;
width: 100%;
height: 500px;
background-color: #000;
}
/* IE7 hack */
*+html #overlay {
position: fixed;
}


Итак что же здесь было изменено? XWiki.Style передает в код JS  габариты изображения, а затем производится масштабирование под высоту 640 пикселей (но так же можно в любой момент изменить значение под себя), это связано с тем, что у моей жены дисплей ноутбука разрешением 1360х768 пикселей. Как сделать так что бы от ОС получить разрешение пользователя в код — я не знаю. Предупреждая дальнейшие замечания к качеству правок в коде — данные правки были сделаны мной на базе знаний полученных в школе на уроках информатики QBasic 4.5 и Borland Pascal 7.0.

Кульминацияция

Теперь у нас есть Вики-движок включающий функционал:
— Блога;
— WYSIWIG редактора;
— Галереи изображений;
— Возможность редактирования и создания новых макросов;
— Возможностью программирования и поддержки синтаксиса популярных Вики-движков;
Интеграцию с Open Office(!) (правда для этого необходимо установить и запустить службу или воспользоваться костылями);

Вот что получилось у меня в качестве примера тестового корпоративного сайта:
08. Пример сайта

Продолжение следует...

Поделиться публикацией
AdBlock похитил этот баннер, но баннеры не зубы — отрастут

Подробнее
Реклама

Комментарии 16

    –5
    Шёл 2015 год. Зловреды всё ещё называли вирусами.
    • НЛО прилетело и опубликовало эту надпись здесь
        0
        Пользовал раньше в качестве таск-трекера и портала с инфой о текущих проектах движок DokuWiki (да и щас личный справочник пишу на нем), только потому, что его можно редактировать без браузера (ведь я известный пользователь Vim, который прикручивает его везде). Просто в один прекрасный день понял, что я не регистрирую задачи и изменения по проектам только потому, что мне лень открывать браузер, искать нужную страницу в вики и редачить ее. С тех пор только DokuWiki.
          0
          Какой-то большой оверхэд получается на фоне того же zim.
            0
            Таки нужен сетевой доступ из браузера другим сотрудникам отдела.
          0
          + {
          + var scale = imgPreloader.height/maxheight
          + imgPreloader.height = maxheight;
          + imgPreloader.width = imgPreloader.width/scale;
          + }

          Код скопирован из коммита?
            0
            Нет, этот вариант изменений в коде сделан мной для удобства при локальном использовании, в коде автора их нет.
              0
              Я про плюсики в начале строки. Это какая-то особенность скриптования для вики?
                0
                нет, по тексту, чуть ниже в спойлере, приведен полностью код для XWiki, в данном же фрагменте я не долго думая использовал особенность всех движков Вики, а именно отображение изменений на странице: сперва я вывел в страницу исходный код, а затем модифицированный и сделал сравнение версий. Плюсы означают новый контент, минусы — удаленный контент.

                Что касается скриптов и API то я бы рекомендовал почитать здесь
                network.xwiki.com/xwiki/bin/view/DocXE52En/ProgrammingOverview
                в разделах посвященных API есть ссылки на документацию, в которой прописано что каждая команда означает.
            0
            Ищу альтернативу медиавики.

            Как в xwiki с разграничением доступа? Можно для отдельных страничек в space разрешить чтение только отдельной группе пользователей? И будет ли при этом работать корректно поиск — в медиавики вроде бы все ACL-расширения костыльные — в поиске выводится все.

            Есть ли возможность автоматически нумеровать статьи и в дальнейшем искать их по номеру — например, KB123456? И чтобы этот номер выводился на самой страничке. Т.е. было и номальный заголовок и номер. В медиавики такой модуль не нашел (можно сделать костылем с mod_rewrite, но поиск по номеру статьи работать не будет).

              0
              Как в xwiki с разграничением доступа? Можно для отдельных страничек в space разрешить чтение только отдельной группе пользователей?
              В xwiki c правами доступа все отлично. Через админку можно создать группы пользователей, раскидать юзеров по группам и разграничить права пользователей к корневым разделам (space того же уровня что и main). Если требуется ограничить права к конкретной странице, то это делается уже на самой странице в меню Edit/Правка --> Access rights/Права доступа. Можно настроить права как для групп, так и для конкретного юзера.

              И будет ли при этом работать корректно поиск — в медиавики вроде бы все ACL-расширения костыльные — в поиске выводится все.
              В xwiki модуль Tags будет выдавать в т.ч. и те теги, которые находятся на скрытых для конкретного пользователя страницах, но в том же поиске — запрещенные страницы отображены не будут. Так же не находит и текст на таких запрещенных страницах.

              Пару слов о поиске, а именно: т.к. русский язык не поддерживается на 100% (хотя интерфейс и переведен, нет проблем с кодировкой и отображением символов, а так же можно сделать многоязычный сайт), словоформы интегрированный поиск не распознает. Для него словоформы такие как «окно» и «окна» (склонения слов, спряжения, мн.ч. и др.) будут считаться разными словами. В то же время модуль поиска ищет текст во вложениях(включая файлы MS Office), но опять же выводит не ссылку на сам документ, а ссылку на страницу, где этот документ вложен.

              Есть ли возможность автоматически нумеровать статьи и в дальнейшем искать их по номеру — например, KB123456?

              На сколько я понимаю это сделать можно (поиск может осуществляться как по тегам, так и по содержимому страниц/вложенных файлов) через тот же velocity, но у меня еще не было нужды копать в этом направлении и потому готового решения предложить Вам сейчас не смогу, вот какие примеры кода на эту тему создание скриптом страниц выдал гугл (боюсь придется писать код самому под себя):
              www.xwiki.org/xwiki/bin/view/FAQ/How+can+I+create+a+new+page+based+on+a+form
              xwiki.475771.n2.nabble.com/Create-a-new-page-from-a-velocity-macro-td7583279.html

              А это библиотека для программирования с помощью скрипта velocity
              platform.xwiki.org/xwiki/bin/view/SRD/Navigation?xpage=embed
                0
                Спасибо.

                Про полномочия, интеграцию с LDAP, маппингом AD-шных групп вчера прочитал и немного понял. На уровне документации все здорово выглядит.

                т.к. русский язык не поддерживается на 100%

                А можете еще о проблемах с русским, кроме словоформ рассказать? С ними понятно — что без нормальных внешних поисковых движков типа сфинкса или еще чего-нибудь поиск всегда будет такой. Поддерживаются ли русские названия страниц и пространств полностью? В медиавики русское название — с пробелами и прочим — можно писать прямо в адресной строке браузера (wiki.ru/wiki/Моя статья), а в примерах XWiki, что я видел, BestPractice почему-то на английском. Не придется ли авторам статей создавать дополнительные названия страниц на английском?

                К сожалению, пока не на работе, испытать негде (дома м.б. попробую), а в песочнице на playground.xwiki.org я не могу править и создавать странички — не появляется кнопка правки после регистрации.
                  0
                  А можете еще о проблемах с русским, кроме словоформ рассказать?

                  Во-первых в начале этой статье я описал способы установки xwiki, самый простой из них — это скачать ZIP архив портативной установки по ссылке:
                  enterprise.xwiki.org/xwiki/bin/view/Main/Download
                  распаковать его, запустить файл start_xwiki.bat (для Windows) / start_xwiki.sh (для Linux) и не закрывать во время работы вылезшую консоль, так же излишне говорить что Java должна быть установлена на Вашем ПК. Эта сборка запускается бессчетное число раз, даже если Вы будете каждый раз перед запуском менять название каталога распакованной xwiki, и таким образом сможете попробовать функционал.

                  Во-вторых поддержка русского языка упирается в механизм работы со ссылками, который для русского языка создает ссылки вида:
                  Wiki Home\Test page\страница с пробелами
                  http://*Ваш_сайт*/xwiki/bin/view/Test+page/%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0+%D1%81+%D0%BF%D1%80%D0%BE%D0%B1%D0%B5%D0%BB%D0%B0%D0%BC%D0%B8
                  На сколько я понимаю — это Unicode, или аналог. В принципе, если не зацикливаться на том что отображается в строке ввода ссылки в браузере, сам движок предложит создать ссылку вида:
                  [[страница с пробелами>>doc:Test page.страница с пробелами]] — это внутренняя ссылке, хотя он переваривает и внешние вида: http://*Ваш_сайт*/*Ваш_путь*

                  В-третьих. Эта реализация русских ссылок упирается в базу данных. Конкретно для этой портативной сборки (в установку в контейнер я еще не пробовал) используется база HSQLDB database. Конкретно ее я тестировал путем загрузки порядка 7Гб информации в виде картинок на страницах и она обрабатывала результаты корректно. Все эти данные пишутся в один единственный файл, расположенный по пути на жестком диске: *каталог установки xwiki*\data\database\xwiki_db.lobs, однако в этой же сборке стоит ограничение на максимальный размер загружаемого файла в 32Мб, а порой требуется вложить бОльшие объемы. Тогда на помощь приходит гугл и выдает следующее решение:
                  comments.gmane.org/gmane.comp.web.wiki.xwiki.user/27679
                  Которое не работает без настройки базы данных, а именно конкретно в этой сборке где-то прошита, я еще не нашел, настройка ограничение на вложение в 32Мб, однако используя следующий костыль (Step 1: Switch to Filesystem attachments.), это ограничение обходится через настройку сохранять вложения напрямую на HDD:
                  extensions.xwiki.org/xwiki/bin/view/Extension/Filesystem+Attachment+Porter

                  Таким образом все вложения, а так же картинки меню и управляющие *.xml, будут хранится на жестком диске в соответствующих каталогах, в отличие от содержания страниц, которые будут по-прежнему хранится в БД. Здесь так же вылезает ограничение файловой таблицы на длину файла с учетом каталогов в 255символов (однако NTFS поддерживает чуть больше, но вот родной explorer, то бишь проводник, работает криво и копирование длинных путей поддерживают только сторонние утилиты, типа Total Commander'а). С учетом того, что все поддерживается напрямую через латиницу и unicode, то для языков отличных от латинской группы пути к файлам на жестком диске превращаются в такого рода:
                  b:\xwiki-7.1-rc-1\data\storage\xwiki\Main\%D0%9E%D0%9E%D0%9E\~this\attachments\01.jpg\01.jpg

                  xwiki движок обрабатывает операции с вложенными файлами с длинным названием корректно, но через ограничение длины пути файловой системы он все же переступить не может и общая длина вложений страниц на сайте упирается в этот анахронизм с 255символами (однако это лишь пути, используя поле Title можно задавать сколь угодно длинное описание страницы, которое будет везде отображаться в самой xwiki, но адресация будет вестись к конкретному короткому названию в путях). К сожалению этот костыль порождает одну единственную проблему — при удалении вложенного файла обрабатываются корректно лишь записи в БД о нем, но физически файл не удаляется с жесткого диска, а так же не отображается в корзине удаленных файлов в xwiki, в отличие от удаленных страниц, которые до удаления из корзины восстановить все же можно (но уже без вложений). Напротив, если принять ограничения в 32Мб на аттач и пользоваться сохранением всей информации, включая вложения, только в БД, то все работает как часы (включая отображение удаленных вложенных-файлов в корзине)

                  Отсюда мини-вывод: если необходимая корректная работа на 100% нужно работать через БД.
                    0
                    либо мириться с прогнозируемыми неувязками…
                      0
                      сегодня постестил немного портативную версию. очень понравилось.

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое