aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--admin/include/functions_upgrade.php2
-rw-r--r--admin/include/plugins.class.php2
-rw-r--r--admin/include/updates.class.php2
-rw-r--r--plugins/TakeATour/admin.php27
-rw-r--r--plugins/TakeATour/css/admin.css15
-rw-r--r--plugins/TakeATour/css/bootstrap-essential.css220
-rw-r--r--plugins/TakeATour/css/bootstrap-tour.min.css19
-rw-r--r--plugins/TakeATour/js/custom-bootstrap-tour-standalone.js1241
-rw-r--r--plugins/TakeATour/language/en_UK/description.txt1
-rw-r--r--plugins/TakeATour/language/en_UK/index.php33
-rw-r--r--plugins/TakeATour/language/en_UK/plugin.lang.php96
-rw-r--r--plugins/TakeATour/language/fr_FR/description.txt1
-rw-r--r--plugins/TakeATour/language/fr_FR/index.php33
-rw-r--r--plugins/TakeATour/language/fr_FR/plugin.lang.php96
-rw-r--r--plugins/TakeATour/main.inc.php133
-rw-r--r--plugins/TakeATour/tours/first_contact/config.inc.php71
-rw-r--r--plugins/TakeATour/tours/first_contact/config_preparse.inc.php59
-rw-r--r--plugins/TakeATour/tours/first_contact/tour.tpl349
-rw-r--r--plugins/TakeATour/tours/scaling/scaling.tpl89
-rw-r--r--plugins/TakeATour/tpl/admin.tpl17
-rw-r--r--plugins/TakeATour/tpl/js_css.tpl3
-rw-r--r--themes/default/template/no_photo_yet.tpl2
-rw-r--r--upgrade.php5
23 files changed, 2509 insertions, 7 deletions
diff --git a/admin/include/functions_upgrade.php b/admin/include/functions_upgrade.php
index 4bd639f85..4580836d0 100644
--- a/admin/include/functions_upgrade.php
+++ b/admin/include/functions_upgrade.php
@@ -76,7 +76,7 @@ function deactivate_non_standard_plugins()
$standard_plugins = array(
'admin_multi_view',
- 'c13y_upgrade',
+ 'TakeATour',
'event_tracer',
'language_switch',
'LocalFilesEditor'
diff --git a/admin/include/plugins.class.php b/admin/include/plugins.class.php
index 7a6bc4036..f1a6ac510 100644
--- a/admin/include/plugins.class.php
+++ b/admin/include/plugins.class.php
@@ -63,7 +63,7 @@ class plugins
var $fs_plugins = array();
var $db_plugins_by_id = array();
var $server_plugins = array();
- var $default_plugins = array('LocalFilesEditor', 'language_switch', 'c13y_upgrade', 'admin_multi_view');
+ var $default_plugins = array('LocalFilesEditor', 'language_switch', 'TakeATour', 'admin_multi_view');
/**
* Initialize $fs_plugins and $db_plugins_by_id
diff --git a/admin/include/updates.class.php b/admin/include/updates.class.php
index 12f5c2223..f0ba94cd1 100644
--- a/admin/include/updates.class.php
+++ b/admin/include/updates.class.php
@@ -45,7 +45,7 @@ class updates
$this->types = array($page);
}
$this->default_themes = array('clear', 'dark', 'Sylvia', 'elegant');
- $this->default_plugins = array('admin_multi_view', 'c13y_upgrade', 'language_switch', 'LocalFilesEditor');
+ $this->default_plugins = array('admin_multi_view', 'TakeATour', 'language_switch', 'LocalFilesEditor');
foreach ($this->types as $type)
{
diff --git a/plugins/TakeATour/admin.php b/plugins/TakeATour/admin.php
new file mode 100644
index 000000000..1f3d44d10
--- /dev/null
+++ b/plugins/TakeATour/admin.php
@@ -0,0 +1,27 @@
+<?php
+
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+global $template, $conf, $user, $page;
+
+load_language('plugin.lang', PHPWG_PLUGINS_PATH .'TakeATour/');
+$template->assign(
+ array(
+ 'F_ACTION' => get_root_url().'admin.php',
+ 'pwg_token' => get_pwg_token()
+ )
+ );
+
+$template->func_combine_css(array(
+ 'path' => 'plugins/TakeATour/css/admin.css',
+ )
+);
+
+if (isset($conf['TakeATour_tour_ignored']) and is_array($conf['TakeATour_tour_ignored']))
+{
+ $template->assign('TAT_tour_ignored', $conf['TakeATour_tour_ignored']);
+}
+$template->set_filename('plugin_admin_content', dirname(__FILE__) .'/tpl/admin.tpl');
+$template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
+
+?> \ No newline at end of file
diff --git a/plugins/TakeATour/css/admin.css b/plugins/TakeATour/css/admin.css
new file mode 100644
index 000000000..e6e2b218a
--- /dev/null
+++ b/plugins/TakeATour/css/admin.css
@@ -0,0 +1,15 @@
+#helpContent .TAT_description {
+ text-align: justify;
+ text-indent: 1em;
+}
+#helpContent form {
+ text-align: center;
+}
+#helpContent form input {
+ width: 50%;
+ margin-top: 10px;
+}
+#helpContent P {
+ text-indent: 1em;
+ text-align: justify;
+} \ No newline at end of file
diff --git a/plugins/TakeATour/css/bootstrap-essential.css b/plugins/TakeATour/css/bootstrap-essential.css
new file mode 100644
index 000000000..ebc6c82f9
--- /dev/null
+++ b/plugins/TakeATour/css/bootstrap-essential.css
@@ -0,0 +1,220 @@
+.tooltip {
+ position: absolute;
+ z-index: 1030;
+ display: block;
+ font-size: 12px;
+ line-height: 1.4;
+ visibility: visible;
+ filter: alpha(opacity=0);
+ opacity: 0;
+}
+.tooltip.in {
+ filter: alpha(opacity=90);
+ opacity: .9;
+}
+.tooltip.top {
+ padding: 5px 0;
+ margin-top: -3px;
+}
+.tooltip.right {
+ padding: 0 5px;
+ margin-left: 3px;
+}
+.tooltip.bottom {
+ padding: 5px 0;
+ margin-top: 3px;
+}
+.tooltip.left {
+ padding: 0 5px;
+ margin-left: -3px;
+}
+.tooltip-inner {
+ max-width: 200px;
+ padding: 3px 8px;
+ color: #fff;
+ text-align: center;
+ text-decoration: none;
+ background-color: #000;
+ border-radius: 4px;
+}
+.tooltip-arrow {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.tooltip.top .tooltip-arrow {
+ bottom: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.top-left .tooltip-arrow {
+ bottom: 0;
+ left: 5px;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.top-right .tooltip-arrow {
+ right: 5px;
+ bottom: 0;
+ border-width: 5px 5px 0;
+ border-top-color: #000;
+}
+.tooltip.right .tooltip-arrow {
+ top: 50%;
+ left: 0;
+ margin-top: -5px;
+ border-width: 5px 5px 5px 0;
+ border-right-color: #000;
+}
+.tooltip.left .tooltip-arrow {
+ top: 50%;
+ right: 0;
+ margin-top: -5px;
+ border-width: 5px 0 5px 5px;
+ border-left-color: #000;
+}
+.tooltip.bottom .tooltip-arrow {
+ top: 0;
+ left: 50%;
+ margin-left: -5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.tooltip.bottom-left .tooltip-arrow {
+ top: 0;
+ left: 5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+ top: 0;
+ right: 5px;
+ border-width: 0 5px 5px;
+ border-bottom-color: #000;
+}
+.popover {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 1010;
+ display: none;
+ max-width: 276px;
+ padding: 1px;
+ text-align: left;
+ white-space: normal;
+ background-color: #fff;
+ background-clip: padding-box;
+ border: 1px solid #ccc;
+ border: 1px solid rgba(0, 0, 0, .2);
+ border-radius: 6px;
+ -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+ box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+}
+.popover.top {
+ margin-top: -10px;
+}
+.popover.right {
+ margin-left: 10px;
+}
+.popover.bottom {
+ margin-top: 10px;
+}
+.popover.left {
+ margin-left: -10px;
+}
+.popover-title {
+ padding: 8px 14px;
+ margin: 0;
+ font-size: 14px;
+ font-weight: normal;
+ line-height: 18px;
+ background-color: #f7f7f7;
+ border-bottom: 1px solid #ebebeb;
+ border-radius: 5px 5px 0 0;
+}
+.popover-content {
+ padding: 9px 14px;
+}
+.popover .arrow,
+.popover .arrow:after {
+ position: absolute;
+ display: block;
+ width: 0;
+ height: 0;
+ border-color: transparent;
+ border-style: solid;
+}
+.popover .arrow {
+ border-width: 11px;
+}
+.popover .arrow:after {
+ content: "";
+ border-width: 10px;
+}
+.popover.top .arrow {
+ bottom: -11px;
+ left: 50%;
+ margin-left: -11px;
+ border-top-color: #999;
+ border-top-color: rgba(0, 0, 0, .25);
+ border-bottom-width: 0;
+}
+.popover.top .arrow:after {
+ bottom: 1px;
+ margin-left: -10px;
+ content: " ";
+ border-top-color: #fff;
+ border-bottom-width: 0;
+}
+.popover.right .arrow {
+ top: 50%;
+ left: -11px;
+ margin-top: -11px;
+ border-right-color: #999;
+ border-right-color: rgba(0, 0, 0, .25);
+ border-left-width: 0;
+}
+.popover.right .arrow:after {
+ bottom: -10px;
+ left: 1px;
+ content: " ";
+ border-right-color: #fff;
+ border-left-width: 0;
+}
+.popover.bottom .arrow {
+ top: -11px;
+ left: 50%;
+ margin-left: -11px;
+ border-top-width: 0;
+ border-bottom-color: #999;
+ border-bottom-color: rgba(0, 0, 0, .25);
+}
+.popover.bottom .arrow:after {
+ top: 1px;
+ margin-left: -10px;
+ content: " ";
+ border-top-width: 0;
+ border-bottom-color: #fff;
+}
+.popover.left .arrow {
+ top: 50%;
+ right: -11px;
+ margin-top: -11px;
+ border-right-width: 0;
+ border-left-color: #999;
+ border-left-color: rgba(0, 0, 0, .25);
+}
+.popover.left .arrow:after {
+ right: 1px;
+ bottom: -10px;
+ content: " ";
+ border-right-width: 0;
+ border-left-color: #fff;
+}
+#TAT_FC_14 .actions {
+ display: block !important;
+} \ No newline at end of file
diff --git a/plugins/TakeATour/css/bootstrap-tour.min.css b/plugins/TakeATour/css/bootstrap-tour.min.css
new file mode 100644
index 000000000..95fab6ad7
--- /dev/null
+++ b/plugins/TakeATour/css/bootstrap-tour.min.css
@@ -0,0 +1,19 @@
+/* ===========================================================
+# bootstrap-tour - v0.8.1
+# http://bootstraptour.com
+# ==============================================================
+# Copyright 2012-2013 Ulrich Sossou
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+.tour-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000;opacity:.8}.tour-step-backdrop{position:relative;z-index:1031;background:inherit}.tour-step-background{position:absolute;z-index:1030;background:inherit;border-radius:6px}.popover[class*=tour-]{z-index:1030}.popover[class*=tour-] .popover-navigation{padding:9px 14px}.popover[class*=tour-] .popover-navigation [data-role=end]{float:right}.popover[class*=tour-] .popover-navigation [data-role=prev],.popover[class*=tour-] .popover-navigation [data-role=next],.popover[class*=tour-] .popover-navigation [data-role=end]{cursor:pointer}.popover[class*=tour-] .popover-navigation [data-role=prev].disabled,.popover[class*=tour-] .popover-navigation [data-role=next].disabled,.popover[class*=tour-] .popover-navigation [data-role=end].disabled{cursor:default}.popover[class*=tour-].orphan{position:fixed;margin-top:0}.popover[class*=tour-].orphan .arrow{display:none} \ No newline at end of file
diff --git a/plugins/TakeATour/js/custom-bootstrap-tour-standalone.js b/plugins/TakeATour/js/custom-bootstrap-tour-standalone.js
new file mode 100644
index 000000000..23c052af6
--- /dev/null
+++ b/plugins/TakeATour/js/custom-bootstrap-tour-standalone.js
@@ -0,0 +1,1241 @@
+/* ===========================================================
+# bootstrap-tour - v0.9.0
+# http://bootstraptour.com
+# ==============================================================
+# Copyright 2012-2013 Ulrich Sossou
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.1.0
+ * http://getbootstrap.com/javascript/#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // TOOLTIP PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Tooltip = function (element, options) {
+ this.type =
+ this.options =
+ this.enabled =
+ this.timeout =
+ this.hoverState =
+ this.$element = null
+
+ this.init('tooltip', element, options)
+ }
+
+ Tooltip.DEFAULTS = {
+ animation: true,
+ placement: 'top',
+ selector: false,
+ template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
+ trigger: 'hover focus',
+ title: '',
+ delay: 0,
+ html: false,
+ container: false
+ }
+
+ Tooltip.prototype.init = function (type, element, options) {
+ this.enabled = true
+ this.type = type
+ this.$element = $(element)
+ this.options = this.getOptions(options)
+
+ var triggers = this.options.trigger.split(' ')
+
+ for (var i = triggers.length; i--;) {
+ var trigger = triggers[i]
+
+ if (trigger == 'click') {
+ this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+ } else if (trigger != 'manual') {
+ var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
+ var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+
+ this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+ this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+ }
+ }
+
+ this.options.selector ?
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+ this.fixTitle()
+ }
+
+ Tooltip.prototype.getDefaults = function () {
+ return Tooltip.DEFAULTS
+ }
+
+ Tooltip.prototype.getOptions = function (options) {
+ options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+ if (options.delay && typeof options.delay == 'number') {
+ options.delay = {
+ show: options.delay,
+ hide: options.delay
+ }
+ }
+
+ return options
+ }
+
+ Tooltip.prototype.getDelegateOptions = function () {
+ var options = {}
+ var defaults = this.getDefaults()
+
+ this._options && $.each(this._options, function (key, value) {
+ if (defaults[key] != value) options[key] = value
+ })
+
+ return options
+ }
+
+ Tooltip.prototype.enter = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'in'
+
+ if (!self.options.delay || !self.options.delay.show) return self.show()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'in') self.show()
+ }, self.options.delay.show)
+ }
+
+ Tooltip.prototype.leave = function (obj) {
+ var self = obj instanceof this.constructor ?
+ obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+ clearTimeout(self.timeout)
+
+ self.hoverState = 'out'
+
+ if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+ self.timeout = setTimeout(function () {
+ if (self.hoverState == 'out') self.hide()
+ }, self.options.delay.hide)
+ }
+
+ Tooltip.prototype.show = function () {
+ var e = $.Event('show.bs.' + this.type)
+
+ if (this.hasContent() && this.enabled) {
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+ var that = this;
+
+ var $tip = this.tip()
+
+ this.setContent()
+
+ if (this.options.animation) $tip.addClass('fade')
+
+ var placement = typeof this.options.placement == 'function' ?
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
+ this.options.placement
+
+ var autoToken = /\s?auto?\s?/i
+ var autoPlace = autoToken.test(placement)
+ if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+ $tip
+ .detach()
+ .css({ top: 0, left: 0, display: 'block' })
+ .addClass(placement)
+
+ this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+
+ var pos = this.getPosition()
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (autoPlace) {
+ var $parent = this.$element.parent()
+
+ var orgPlacement = placement
+ var docScroll = document.documentElement.scrollTop || document.body.scrollTop
+ var parentWidth = this.options.container == 'body' ? window.innerWidth : $parent.outerWidth()
+ var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
+ var parentLeft = this.options.container == 'body' ? 0 : $parent.offset().left
+
+ placement = placement == 'bottom' && pos.top + pos.height + actualHeight - docScroll > parentHeight ? 'top' :
+ placement == 'top' && pos.top - docScroll - actualHeight < 0 ? 'bottom' :
+ placement == 'right' && pos.right + actualWidth > parentWidth ? 'left' :
+ placement == 'left' && pos.left - actualWidth < parentLeft ? 'right' :
+ placement
+
+ $tip
+ .removeClass(orgPlacement)
+ .addClass(placement)
+ }
+
+ var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+ this.applyPlacement(calculatedOffset, placement)
+ this.hoverState = null
+
+ var complete = function() {
+ that.$element.trigger('shown.bs.' + that.type)
+ }
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $tip
+ .one($.support.transition.end, complete)
+ .emulateTransitionEnd(150) :
+ complete()
+ }
+ }
+
+ Tooltip.prototype.applyPlacement = function (offset, placement) {
+ var replace
+ var $tip = this.tip()
+ var width = $tip[0].offsetWidth
+ var height = $tip[0].offsetHeight
+
+ // manually read margins because getBoundingClientRect includes difference
+ var marginTop = parseInt($tip.css('margin-top'), 10)
+ var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+ // we must check for NaN for ie 8/9
+ if (isNaN(marginTop)) marginTop = 0
+ if (isNaN(marginLeft)) marginLeft = 0
+
+ offset.top = offset.top + marginTop
+ offset.left = offset.left + marginLeft
+
+ // $.fn.offset doesn't round pixel values
+ // so we use setOffset directly with our own function B-0
+ $.offset.setOffset($tip[0], $.extend({
+ using: function (props) {
+ $tip.css({
+ top: Math.round(props.top),
+ left: Math.round(props.left)
+ })
+ }
+ }, offset), 0)
+
+ $tip.addClass('in')
+
+ // check to see if placing tip in new offset caused the tip to resize itself
+ var actualWidth = $tip[0].offsetWidth
+ var actualHeight = $tip[0].offsetHeight
+
+ if (placement == 'top' && actualHeight != height) {
+ replace = true
+ offset.top = offset.top + height - actualHeight
+ }
+
+ if (/bottom|top/.test(placement)) {
+ var delta = 0
+
+ if (offset.left < 0) {
+ delta = offset.left * -2
+ offset.left = 0
+
+ $tip.offset(offset)
+
+ actualWidth = $tip[0].offsetWidth
+ actualHeight = $tip[0].offsetHeight
+ }
+
+ this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
+ } else {
+ this.replaceArrow(actualHeight - height, actualHeight, 'top')
+ }
+
+ if (replace) $tip.offset(offset)
+ }
+
+ Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
+ this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
+ }
+
+ Tooltip.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+
+ $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+ $tip.removeClass('fade in top bottom left right')
+ }
+
+ Tooltip.prototype.hide = function () {
+ var that = this
+ var $tip = this.tip()
+ var e = $.Event('hide.bs.' + this.type)
+
+ function complete() {
+ if (that.hoverState != 'in') $tip.detach()
+ that.$element.trigger('hidden.bs.' + that.type)
+ }
+
+ this.$element.trigger(e)
+
+ if (e.isDefaultPrevented()) return
+
+ $tip.removeClass('in')
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ $tip
+ .one($.support.transition.end, complete)
+ .emulateTransitionEnd(150) :
+ complete()
+
+ this.hoverState = null
+
+ return this
+ }
+
+ Tooltip.prototype.fixTitle = function () {
+ var $e = this.$element
+ if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
+ $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+ }
+ }
+
+ Tooltip.prototype.hasContent = function () {
+ return this.getTitle()
+ }
+
+ Tooltip.prototype.getPosition = function () {
+ var el = this.$element[0]
+ return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
+ width: el.offsetWidth,
+ height: el.offsetHeight
+ }, this.$element.offset())
+ }
+
+ Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+ return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
+ placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+ /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
+ }
+
+ Tooltip.prototype.getTitle = function () {
+ var title
+ var $e = this.$element
+ var o = this.options
+
+ title = $e.attr('data-original-title')
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
+
+ return title
+ }
+
+ Tooltip.prototype.tip = function () {
+ return this.$tip = this.$tip || $(this.options.template)
+ }
+
+ Tooltip.prototype.arrow = function () {
+ return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
+ }
+
+ Tooltip.prototype.validate = function () {
+ if (!this.$element[0].parentNode) {
+ this.hide()
+ this.$element = null
+ this.options = null
+ }
+ }
+
+ Tooltip.prototype.enable = function () {
+ this.enabled = true
+ }
+
+ Tooltip.prototype.disable = function () {
+ this.enabled = false
+ }
+
+ Tooltip.prototype.toggleEnabled = function () {
+ this.enabled = !this.enabled
+ }
+
+ Tooltip.prototype.toggle = function (e) {
+ var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
+ self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+ }
+
+ Tooltip.prototype.destroy = function () {
+ clearTimeout(this.timeout)
+ this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
+ }
+
+
+ // TOOLTIP PLUGIN DEFINITION
+ // =========================
+
+ var old = $.fn.tooltip
+
+ $.fn.tooltip = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.tooltip')
+ var options = typeof option == 'object' && option
+
+ if (!data && option == 'destroy') return
+ if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.tooltip.Constructor = Tooltip
+
+
+ // TOOLTIP NO CONFLICT
+ // ===================
+
+ $.fn.tooltip.noConflict = function () {
+ $.fn.tooltip = old
+ return this
+ }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: popover.js v3.1.0
+ * http://getbootstrap.com/javascript/#popovers
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+ 'use strict';
+
+ // POPOVER PUBLIC CLASS DEFINITION
+ // ===============================
+
+ var Popover = function (element, options) {
+ this.init('popover', element, options)
+ }
+
+ if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+ Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
+ placement: 'right',
+ trigger: 'click',
+ content: '',
+ template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+ })
+
+
+ // NOTE: POPOVER EXTENDS tooltip.js
+ // ================================
+
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+ Popover.prototype.constructor = Popover
+
+ Popover.prototype.getDefaults = function () {
+ return Popover.DEFAULTS
+ }
+
+ Popover.prototype.setContent = function () {
+ var $tip = this.tip()
+ var title = this.getTitle()
+ var content = this.getContent()
+
+ $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+ $tip.find('.popover-content')[ // we use append for html objects to maintain js events
+ this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+ ](content)
+
+ $tip.removeClass('fade top bottom left right in')
+
+ // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+ // this manually by checking the contents.
+ if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+ }
+
+ Popover.prototype.hasContent = function () {
+ return this.getTitle() || this.getContent()
+ }
+
+ Popover.prototype.getContent = function () {
+ var $e = this.$element
+ var o = this.options
+
+ return $e.attr('data-content')
+ || (typeof o.content == 'function' ?
+ o.content.call($e[0]) :
+ o.content)
+ }
+
+ Popover.prototype.arrow = function () {
+ return this.$arrow = this.$arrow || this.tip().find('.arrow')
+ }
+
+ Popover.prototype.tip = function () {
+ if (!this.$tip) this.$tip = $(this.options.template)
+ return this.$tip
+ }
+
+
+ // POPOVER PLUGIN DEFINITION
+ // =========================
+
+ var old = $.fn.popover
+
+ $.fn.popover = function (option) {
+ return this.each(function () {
+ var $this = $(this)
+ var data = $this.data('bs.popover')
+ var options = typeof option == 'object' && option
+
+ if (!data && option == 'destroy') return
+ if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.popover.Constructor = Popover
+
+
+ // POPOVER NO CONFLICT
+ // ===================
+
+ $.fn.popover.noConflict = function () {
+ $.fn.popover = old
+ return this
+ }
+
+}(jQuery);
+
+(function($, window) {
+ var Tour, document;
+ document = window.document;
+ Tour = (function() {
+ function Tour(options) {
+ this._options = $.extend({
+ name: "tour",
+ steps: [],
+ container: "body",
+ keyboard: true,
+ storage: window.localStorage,
+ debug: false,
+ backdrop: false,
+ redirect: true,
+ orphan: false,
+ duration: false,
+ basePath: "",
+ template: "<div class='popover'> <div class='arrow'></div> <h3 class='popover-title'></h3> <div class='popover-content'></div> <div class='popover-navigation'> <div class='btn-group'> <button class='btn btn-sm btn-default' data-role='prev'>&laquo; Prev</button> <button class='btn btn-sm btn-default' data-role='next'>Next &raquo;</button> <button class='btn btn-sm btn-default' data-role='pause-resume' data-pause-text='Pause' data-resume-text='Resume'>Pause</button> </div> <button class='btn btn-sm btn-default' data-role='end'>End tour</button> </div> </div>",
+ afterSetState: function(key, value) {},
+ afterGetState: function(key, value) {},
+ afterRemoveState: function(key) {},
+ onStart: function(tour) {},
+ onEnd: function(tour) {},
+ onShow: function(tour) {},
+ onShown: function(tour) {},
+ onHide: function(tour) {},
+ onHidden: function(tour) {},
+ onNext: function(tour) {},
+ onPrev: function(tour) {},
+ onPause: function(tour, duration) {},
+ onResume: function(tour, duration) {}
+ }, options);
+ this._force = false;
+ this._inited = false;
+ this.backdrop = {
+ overlay: null,
+ $element: null,
+ $background: null,
+ backgroundShown: false,
+ overlayElementShown: false
+ };
+ this;
+ }
+
+ Tour.prototype.addSteps = function(steps) {
+ var step, _i, _len;
+ for (_i = 0, _len = steps.length; _i < _len; _i++) {
+ step = steps[_i];
+ this.addStep(step);
+ }
+ return this;
+ };
+
+ Tour.prototype.addStep = function(step) {
+ this._options.steps.push(step);
+ return this;
+ };
+
+ Tour.prototype.getStep = function(i) {
+ if (this._options.steps[i] != null) {
+ return $.extend({
+ id: "step-" + i,
+ path: "",
+ placement: "right",
+ title: "",
+ content: "<p></p>",
+ next: i === this._options.steps.length - 1 ? -1 : i + 1,
+ prev: i - 1,
+ animation: true,
+ container: this._options.container,
+ backdrop: this._options.backdrop,
+ redirect: this._options.redirect,
+ orphan: this._options.orphan,
+ duration: this._options.duration,
+ template: this._options.template,
+ onShow: this._options.onShow,
+ onShown: this._options.onShown,
+ onHide: this._options.onHide,
+ onHidden: this._options.onHidden,
+ onNext: this._options.onNext,
+ onPrev: this._options.onPrev,
+ onPause: this._options.onPause,
+ onResume: this._options.onResume
+ }, this._options.steps[i]);
+ }
+ };
+
+ Tour.prototype.init = function(force) {
+ this._force = force;
+ if (this.ended()) {
+ this._debug("Tour ended, init prevented.");
+ return this;
+ }
+ this.setCurrentStep();
+ this._initMouseNavigation();
+ this._initKeyboardNavigation();
+ this._onResize((function(_this) {
+ return function() {
+ return _this.showStep(_this._current);
+ };
+ })(this));
+ if (this._current !== null) {
+ this.showStep(this._current);
+ }
+ this._inited = true;
+ return this;
+ };
+
+ Tour.prototype.start = function(force) {
+ var promise;
+ if (force == null) {
+ force = false;
+ }
+ if (!this._inited) {
+ this.init(force);
+ }
+ if (this._current === null) {
+ promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0);
+ this._callOnPromiseDone(promise, this.showStep, 0);
+ }
+ return this;
+ };
+
+ Tour.prototype.next = function() {
+ var promise;
+ promise = this.hideStep(this._current);
+ return this._callOnPromiseDone(promise, this._showNextStep);
+ };
+
+ Tour.prototype.prev = function() {
+ var promise;
+ promise = this.hideStep(this._current);
+ return this._callOnPromiseDone(promise, this._showPrevStep);
+ };
+
+ Tour.prototype.goTo = function(i) {
+ var promise;
+ promise = this.hideStep(this._current);
+ return this._callOnPromiseDone(promise, this.showStep, i);
+ };
+
+ Tour.prototype.end = function() {
+ var endHelper, promise;
+ endHelper = (function(_this) {
+ return function(e) {
+ $(document).off("click.tour-" + _this._options.name);
+ $(document).off("keyup.tour-" + _this._options.name);
+ $(window).off("resize.tour-" + _this._options.name);
+ _this._setState("end", "yes");
+ _this._inited = false;
+ _this._force = false;
+ _this._clearTimer();
+ if (_this._options.onEnd != null) {
+ return _this._options.onEnd(_this);
+ }
+ };
+ })(this);
+ promise = this.hideStep(this._current);
+ return this._callOnPromiseDone(promise, endHelper);
+ };
+
+ Tour.prototype.ended = function() {
+ return !this._force && !!this._getState("end");
+ };
+
+ Tour.prototype.restart = function() {
+ this._removeState("current_step");
+ this._removeState("end");
+ this.setCurrentStep(0);
+ return this.start();
+ };
+
+ Tour.prototype.pause = function() {
+ var step;
+ step = this.getStep(this._current);
+ if (!(step && step.duration)) {
+ return this;
+ }
+ this._paused = true;
+ this._duration -= new Date().getTime() - this._start;
+ window.clearTimeout(this._timer);
+ this._debug("Paused/Stopped step " + (this._current + 1) + " timer (" + this._duration + " remaining).");
+ if (step.onPause != null) {
+ return step.onPause(this, this._duration);
+ }
+ };
+
+ Tour.prototype.resume = function() {
+ var step;
+ step = this.getStep(this._current);
+ if (!(step && step.duration)) {
+ return this;
+ }
+ this._paused = false;
+ this._start = new Date().getTime();
+ this._duration = this._duration || step.duration;
+ this._timer = window.setTimeout((function(_this) {
+ return function() {
+ if (_this._isLast()) {
+ return _this.next();
+ } else {
+ return _this.end();
+ }
+ };
+ })(this), this._duration);
+ this._debug("Started step " + (this._current + 1) + " timer with duration " + this._duration);
+ if ((step.onResume != null) && this._duration !== step.duration) {
+ return step.onResume(this, this._duration);
+ }
+ };
+
+ Tour.prototype.hideStep = function(i) {
+ var hideStepHelper, promise, step;
+ step = this.getStep(i);
+ if (!step) {
+ return;
+ }
+ this._clearTimer();
+ promise = this._makePromise(step.onHide != null ? step.onHide(this, i) : void 0);
+ hideStepHelper = (function(_this) {
+ return function(e) {
+ var $element;
+ $element = $(step.element);
+ if (!($element.data("bs.popover") || $element.data("popover"))) {
+ $element = $("body");
+ }
+ $element.popover("destroy").removeClass("tour-" + _this._options.name + "-element tour-" + _this._options.name + "-" + i + "-element");
+ if (step.reflex) {
+ $element.css("cursor", "").off("click.tour-" + _this._options.name);
+ }
+ if (step.backdrop) {
+ _this._hideBackdrop();
+ }
+ if (step.onHidden != null) {
+ return step.onHidden(_this);
+ }
+ };
+ })(this);
+ this._callOnPromiseDone(promise, hideStepHelper);
+ return promise;
+ };
+
+ Tour.prototype.showStep = function(i) {
+ var promise, showStepHelper, skipToPrevious, step;
+ if (this.ended()) {
+ this._debug("Tour ended, showStep prevented.");
+ return this;
+ }
+ step = this.getStep(i);
+ if (!step) {
+ return;
+ }
+ skipToPrevious = i < this._current;
+ promise = this._makePromise(step.onShow != null ? step.onShow(this, i) : void 0);
+ showStepHelper = (function(_this) {
+ return function(e) {
+ var current_path, path;
+ _this.setCurrentStep(i);
+ path = (function() {
+ switch ({}.toString.call(step.path)) {
+ case "[object Function]":
+ return step.path();
+ case "[object String]":
+ return this._options.basePath + step.path;
+ default:
+ return step.path;
+ }
+ }).call(_this);
+ current_path = document.location.href;
+ if (_this._isRedirect(path, current_path)) {
+ if (toString.call(path) === "[object RegExp]") {
+ _this._redirect(step, path);
+ }
+ else {
+ path = document.location.protocol+'//'+path;
+ _this._redirect(step, path);
+ }
+ return;
+ }
+ if (_this._isOrphan(step)) {
+ if (!step.orphan) {
+ _this._debug("Skip the orphan step " + (_this._current + 1) + ". Orphan option is false and the element doesn't exist or is hidden.");
+ if (skipToPrevious) {
+ _this._showPrevStep();
+ } else {
+ _this._showNextStep();
+ }
+ return;
+ }
+ _this._debug("Show the orphan step " + (_this._current + 1) + ". Orphans option is true.");
+ }
+ if (step.title === "" & step.content === "") {
+ if (skipToPrevious) {
+ _this._showPrevStep();
+ } else {
+ _this._showNextStep();
+ }
+ return;
+ }
+ if (step.backdrop) {
+ _this._showBackdrop(!_this._isOrphan(step) ? step.element : void 0);
+ }
+ _this._scrollIntoView(step.element, function() {
+ if ((step.element != null) && step.backdrop) {
+ _this._showOverlayElement(step.element);
+ }
+ _this._showPopover(step, i);
+ if (step.onShown != null) {
+ step.onShown(_this);
+ }
+ return _this._debug("Step " + (_this._current + 1) + " of " + _this._options.steps.length);
+ });
+ if (step.duration) {
+ return _this.resume();
+ }
+ };
+ })(this);
+ this._callOnPromiseDone(promise, showStepHelper);
+ return promise;
+ };
+
+ Tour.prototype.getCurrentStep = function() {
+ return this._current;
+ };
+
+ Tour.prototype.setCurrentStep = function(value) {
+ if (value != null) {
+ this._current = value;
+ this._setState("current_step", value);
+ } else {
+ this._current = this._getState("current_step");
+ this._current = this._current === null ? null : parseInt(this._current, 10);
+ }
+ return this;
+ };
+
+ Tour.prototype._setState = function(key, value) {
+ var e, keyName;
+ if (this._options.storage) {
+ keyName = "" + this._options.name + "_" + key;
+ try {
+ this._options.storage.setItem(keyName, value);
+ } catch (_error) {
+ e = _error;
+ if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
+ this.debug("LocalStorage quota exceeded. State storage failed.");
+ }
+ }
+ return this._options.afterSetState(keyName, value);
+ } else {
+ if (this._state == null) {
+ this._state = {};
+ }
+ return this._state[key] = value;
+ }
+ };
+
+ Tour.prototype._removeState = function(key) {
+ var keyName;
+ if (this._options.storage) {
+ keyName = "" + this._options.name + "_" + key;
+ this._options.storage.removeItem(keyName);
+ return this._options.afterRemoveState(keyName);
+ } else {
+ if (this._state != null) {
+ return delete this._state[key];
+ }
+ }
+ };
+
+ Tour.prototype._getState = function(key) {
+ var keyName, value;
+ if (this._options.storage) {
+ keyName = "" + this._options.name + "_" + key;
+ value = this._options.storage.getItem(keyName);
+ } else {
+ if (this._state != null) {
+ value = this._state[key];
+ }
+ }
+ if (value === void 0 || value === "null") {
+ value = null;
+ }
+ this._options.afterGetState(key, value);
+ return value;
+ };
+
+ Tour.prototype._showNextStep = function() {
+ var promise, showNextStepHelper, step;
+ step = this.getStep(this._current);
+ showNextStepHelper = (function(_this) {
+ return function(e) {
+ return _this.showStep(step.next);
+ };
+ })(this);
+ promise = this._makePromise(step.onNext != null ? step.onNext(this) : void 0);
+ return this._callOnPromiseDone(promise, showNextStepHelper);
+ };
+
+ Tour.prototype._showPrevStep = function() {
+ var promise, showPrevStepHelper, step;
+ step = this.getStep(this._current);
+ showPrevStepHelper = (function(_this) {
+ return function(e) {
+ return _this.showStep(step.prev);
+ };
+ })(this);
+ promise = this._makePromise(step.onPrev != null ? step.onPrev(this) : void 0);
+ return this._callOnPromiseDone(promise, showPrevStepHelper);
+ };
+
+ Tour.prototype._debug = function(text) {
+ if (this._options.debug) {
+ return window.console.log("Bootstrap Tour '" + this._options.name + "' | " + text);
+ }
+ };
+
+ Tour.prototype._isRedirect = function(path, currentPath) {
+ return (path != null) && path !== "" && ((toString.call(path) === "[object RegExp]" && !path.test(currentPath)) || (toString.call(path) === "[object String]" && path !== currentPath.replace("http://", "").replace("https://", "")));
+ };
+
+ Tour.prototype._redirect = function(step, path) {
+ if ($.isFunction(step.redirect)) {
+ return step.redirect.call(this, path);
+ } else if (step.redirect === true) {
+ this._debug("Redirect to " + path);
+ return document.location.href = path;
+ }
+ };
+
+ Tour.prototype._isOrphan = function(step) {
+ return (step.element == null) || !$(step.element).length || $(step.element).is(":hidden") && ($(step.element)[0].namespaceURI !== "http://www.w3.org/2000/svg");
+ };
+
+ Tour.prototype._isLast = function() {
+ return this._current < this._options.steps.length - 1;
+ };
+
+ Tour.prototype._showPopover = function(step, i) {
+ var $element, $navigation, $template, $tip, isOrphan, options;
+ options = $.extend({}, this._options);
+ $template = $.isFunction(step.template) ? $(step.template(i, step)) : $(step.template);
+ $navigation = $template.find(".popover-navigation");
+ isOrphan = this._isOrphan(step);
+ if (isOrphan) {
+ step.element = "body";
+ step.placement = "top";
+ $template = $template.addClass("orphan");
+ }
+ $element = $(step.element);
+ $template.addClass("tour-" + this._options.name + " tour-" + this._options.name + "-" + i);
+ $element.addClass("tour-" + this._options.name + "-element tour-" + this._options.name + "-" + i + "-element");
+ if (step.options) {
+ $.extend(options, step.options);
+ }
+ if (step.reflex & !isOrphan) {
+ $element.css("cursor", "pointer").on("click.tour-" + this._options.name, (function(_this) {
+ return function() {
+ if (_this._isLast()) {
+ return _this.next();
+ } else {
+ return _this.end();
+ }
+ };
+ })(this));
+ }
+ if (step.prev < 0) {
+ $navigation.find("[data-role='prev']").addClass("disabled");
+ }
+ if (step.next < 0) {
+ $navigation.find("[data-role='next']").addClass("disabled");
+ }
+ if (!step.duration) {
+ $navigation.find("[data-role='pause-resume']").remove();
+ }
+ step.template = $template.clone().wrap("<div>").parent().html();
+ $element.popover({
+ placement: step.placement,
+ trigger: "manual",
+ title: step.title,
+ content: step.content,
+ html: true,
+ animation: step.animation,
+ container: step.container,
+ template: step.template,
+ selector: step.element
+ }).popover("show");
+ $tip = $element.data("bs.popover") ? $element.data("bs.popover").tip() : $element.data("popover").tip();
+ $tip.attr("id", step.id);
+ this._reposition($tip, step);
+ if (isOrphan) {
+ return this._center($tip);
+ }
+ };
+
+ Tour.prototype._reposition = function($tip, step) {
+ var offsetBottom, offsetHeight, offsetRight, offsetWidth, originalLeft, originalTop, tipOffset;
+ offsetWidth = $tip[0].offsetWidth;
+ offsetHeight = $tip[0].offsetHeight;
+ tipOffset = $tip.offset();
+ originalLeft = tipOffset.left;
+ originalTop = tipOffset.top;
+ offsetBottom = $(document).outerHeight() - tipOffset.top - $tip.outerHeight();
+ if (offsetBottom < 0) {
+ tipOffset.top = tipOffset.top + offsetBottom;
+ }
+ offsetRight = $("html").outerWidth() - tipOffset.left - $tip.outerWidth();
+ if (offsetRight < 0) {
+ tipOffset.left = tipOffset.left + offsetRight;
+ }
+ if (tipOffset.top < 0) {
+ tipOffset.top = 0;
+ }
+ if (tipOffset.left < 0) {
+ tipOffset.left = 0;
+ }
+ $tip.offset(tipOffset);
+ if (step.placement === "bottom" || step.placement === "top") {
+ if (originalLeft !== tipOffset.left) {
+ return this._replaceArrow($tip, (tipOffset.left - originalLeft) * 2, offsetWidth, "left");
+ }
+ } else {
+ if (originalTop !== tipOffset.top) {
+ return this._replaceArrow($tip, (tipOffset.top - originalTop) * 2, offsetHeight, "top");
+ }
+ }
+ };
+
+ Tour.prototype._center = function($tip) {
+ return $tip.css("top", $(window).outerHeight() / 2 - $tip.outerHeight() / 2);
+ };
+
+ Tour.prototype._replaceArrow = function($tip, delta, dimension, position) {
+ return $tip.find(".arrow").css(position, delta ? 50 * (1 - delta / dimension) + "%" : "");
+ };
+
+ Tour.prototype._scrollIntoView = function(element, callback) {
+ var $element, $window, counter, offsetTop, scrollTop, windowHeight;
+ $element = $(element);
+ if (!$element.length) {
+ return callback();
+ }
+ $window = $(window);
+ offsetTop = $element.offset().top;
+ windowHeight = $window.height();
+ scrollTop = Math.max(0, offsetTop - (windowHeight / 2));
+ this._debug("Scroll into view. ScrollTop: " + scrollTop + ". Element offset: " + offsetTop + ". Window height: " + windowHeight + ".");
+ counter = 0;
+ return $("body,html").stop(true, true).animate({
+ scrollTop: Math.ceil(scrollTop)
+ }, (function(_this) {
+ return function() {
+ if (++counter === 2) {
+ callback();
+ return _this._debug("Scroll into view. Animation end element offset: " + ($element.offset().top) + ". Window height: " + ($window.height()) + ".");
+ }
+ };
+ })(this));
+ };
+
+ Tour.prototype._onResize = function(callback, timeout) {
+ return $(window).on("resize.tour-" + this._options.name, function() {
+ clearTimeout(timeout);
+ return timeout = setTimeout(callback, 100);
+ });
+ };
+
+ Tour.prototype._initMouseNavigation = function() {
+ var _this;
+ _this = this;
+ return $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']:not(.disabled)").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']:not(.disabled)").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']:not(.disabled)", (function(_this) {
+ return function(e) {
+ e.preventDefault();
+ return _this.next();
+ };
+ })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']:not(.disabled)", (function(_this) {
+ return function(e) {
+ e.preventDefault();
+ return _this.prev();
+ };
+ })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']", (function(_this) {
+ return function(e) {
+ e.preventDefault();
+ return _this.end();
+ };
+ })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']", function(e) {
+ var $this;
+ e.preventDefault();
+ $this = $(this);
+ $this.text(_this._paused ? $this.data("pause-text") : $this.data("resume-text"));
+ if (_this._paused) {
+ return _this.resume();
+ } else {
+ return _this.pause();
+ }
+ });
+ };
+
+ Tour.prototype._initKeyboardNavigation = function() {
+ if (!this._options.keyboard) {
+ return;
+ }
+ return $(document).on("keyup.tour-" + this._options.name, (function(_this) {
+ return function(e) {
+ if (!e.which) {
+ return;
+ }
+ switch (e.which) {
+ case 39:
+ e.preventDefault();
+ if (_this._isLast()) {
+ return _this.next();
+ } else {
+ return _this.end();
+ }
+ break;
+ case 37:
+ e.preventDefault();
+ if (_this._current > 0) {
+ return _this.prev();
+ }
+ break;
+ case 27:
+ e.preventDefault();
+ return _this.end();
+ }
+ };
+ })(this));
+ };
+
+ Tour.prototype._makePromise = function(result) {
+ if (result && $.isFunction(result.then)) {
+ return result;
+ } else {
+ return null;
+ }
+ };
+
+ Tour.prototype._callOnPromiseDone = function(promise, cb, arg) {
+ if (promise) {
+ return promise.then((function(_this) {
+ return function(e) {
+ return cb.call(_this, arg);
+ };
+ })(this));
+ } else {
+ return cb.call(this, arg);
+ }
+ };
+
+ Tour.prototype._showBackdrop = function(element) {
+ if (this.backdrop.backgroundShown) {
+ return;
+ }
+ this.backdrop = $("<div/>", {
+ "class": "tour-backdrop"
+ });
+ this.backdrop.backgroundShown = true;
+ return $("body").append(this.backdrop);
+ };
+
+ Tour.prototype._hideBackdrop = function() {
+ this._hideOverlayElement();
+ return this._hideBackground();
+ };
+
+ Tour.prototype._hideBackground = function() {
+ this.backdrop.remove();
+ this.backdrop.overlay = null;
+ return this.backdrop.backgroundShown = false;
+ };
+
+ Tour.prototype._showOverlayElement = function(element) {
+ var $background, $element, offset;
+ $element = $(element);
+ if (!$element || $element.length === 0 || this.backdrop.overlayElementShown) {
+ return;
+ }
+ this.backdrop.overlayElementShown = true;
+ $background = $("<div/>");
+ offset = $element.offset();
+ offset.top = offset.top;
+ offset.left = offset.left;
+ $background.width($element.innerWidth()).height($element.innerHeight()).addClass("tour-step-background").offset(offset);
+ $element.addClass("tour-step-backdrop");
+ $("body").append($background);
+ this.backdrop.$element = $element;
+ return this.backdrop.$background = $background;
+ };
+
+ Tour.prototype._hideOverlayElement = function() {
+ if (!this.backdrop.overlayElementShown) {
+ return;
+ }
+ this.backdrop.$element.removeClass("tour-step-backdrop");
+ this.backdrop.$background.remove();
+ this.backdrop.$element = null;
+ this.backdrop.$background = null;
+ return this.backdrop.overlayElementShown = false;
+ };
+
+ Tour.prototype._clearTimer = function() {
+ window.clearTimeout(this._timer);
+ this._timer = null;
+ return this._duration = null;
+ };
+
+ return Tour;
+
+ })();
+ return window.Tour = Tour;
+})(jQuery, window);
diff --git a/plugins/TakeATour/language/en_UK/description.txt b/plugins/TakeATour/language/en_UK/description.txt
new file mode 100644
index 000000000..4c1795604
--- /dev/null
+++ b/plugins/TakeATour/language/en_UK/description.txt
@@ -0,0 +1 @@
+Visit your Piwigo to discover its features. This plugin has multiple thematic tours for beginners and advanced users. \ No newline at end of file
diff --git a/plugins/TakeATour/language/en_UK/index.php b/plugins/TakeATour/language/en_UK/index.php
new file mode 100644
index 000000000..db1eae0d9
--- /dev/null
+++ b/plugins/TakeATour/language/en_UK/index.php
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
diff --git a/plugins/TakeATour/language/en_UK/plugin.lang.php b/plugins/TakeATour/language/en_UK/plugin.lang.php
new file mode 100644
index 000000000..6ad05afcf
--- /dev/null
+++ b/plugins/TakeATour/language/en_UK/plugin.lang.php
@@ -0,0 +1,96 @@
+<?php
+$lang['First Contact'] = 'First Contact';
+$lang['Start the Tour'] = 'Start the Tour';
+$lang['Visit your Piwigo!'] = 'Visit your Piwigo!';
+$lang['Take a tour and discover the features of your Piwigo gallery » Go to the available tours'] = 'Take a tour and discover the features of your Piwigo gallery » Go to the available tours';
+$lang['TAT_descrp'] = 'Welcome! Here are listed all the available tours to discover the features of your Piwigo gallery.<br>Launch a tour below, then follow the instructions. Click Next/Prev (or use the arrows of your keyboard) to navigate during a tour. During a tour, if you go to an other page of the administration, you will be redirected to the current page of the Tour. If you are stuck and can\'t end the tour, going to <em>Plugins » Take A Tour</em> will end the tour.';
+$lang['takeatour_configpage'] = 'Take A Tour » List of Tours';
+$lang['first_contact_descrp'] = 'Recommended for beginners, this tour introduce you Piwigo, its basic features. It will start by adding pictures, then manage them. The tour continues with album management and permissions, and ends on the customization using the configuration, the themes and the plugins.';
+$lang['first_contact_title1'] = 'Welcome in your Piwigo gallery';
+$lang['first_contact_stp1'] = 'Hello! I will be your guide to discover Piwigo. Please follow my instructions, and click Next (or use the arrows of your keyboard) to navigate. If you go to an other page of the administration, you will be redirected to the current page of the Tour. If you are stuck and can\'t end the tour, going to <em>Plugins » Take A Tour</em> will end the tour.<br>Let\'s start by adding pictures!';
+$lang['first_contact_title2'] = '';
+$lang['first_contact_stp2'] = 'The link is here. Click Next to continue';
+$lang['first_contact_title3'] = 'Add Photo Page';
+$lang['first_contact_stp3'] = 'This first tab is where you add photos directly from your browser. The other tabs are about the other ways to upload photos';
+$lang['first_contact_title4'] = 'Lets add photo!';
+$lang['first_contact_stp4'] = 'First choose an album; create one if there is no album yet.';
+$lang['first_contact_title5'] = '';
+$lang['first_contact_stp5'] = 'Then click the button to select photos to send from your computer';
+$lang['first_contact_title6'] = '';
+$lang['first_contact_stp6'] = 'You see that photos are being listed. Add at least 2 pictures and when you\'re ready click the button Start Upload';
+$lang['first_contact_title7'] = '';
+$lang['first_contact_stp7'] = 'Here a summary of your uploaded pictures. See that Piwigo has generated itself the thumbnails. You can know add more photos with the link at the bottom, edit the properties of a picture by clicking on it, or click to manage all the uploaded pictures in the Batch Manager...';
+$lang['first_contact_title8'] = '';
+$lang['first_contact_stp8'] = 'Let\'s edit them! Click on the link. If you don\'t see it click Prev to add at least 2 photos.';
+$lang['first_contact_title9'] = 'The Batch Manager';
+$lang['first_contact_stp9'] = 'You are know in the Batch Manager, where you can batch edit multiple pictures. Here the Caddy is set as a filter because we comes from the upload result page.';
+$lang['first_contact_title10'] = '';
+$lang['first_contact_stp10'] = 'Here is the link to directly access to your caddy: that/s a tool for administrators to easily add pictures to a set in order to edit them in the Batch Manager. You can add photos to the caddy from the public picture page when logged as an admin, or using the action \"Add to caddy\" on the Batch Manager';
+$lang['first_contact_title11'] = 'How to edit a photos';
+$lang['first_contact_stp11'] = 'So you can select from here one or more photos';
+$lang['first_contact_title12'] = '';
+$lang['first_contact_stp12'] = 'then edit them using and action. But for instance, you can\'t -for now- batch edit descriptions since they are mostly unique';
+$lang['first_contact_title13'] = '';
+$lang['first_contact_stp13'] = 'You can edit descriptions and more from the batch manager in unit mode. But for now, let\'s stay in the global mode';
+$lang['first_contact_title14'] = '';
+$lang['first_contact_stp14'] = 'We will see now the edition page of one picture. That page is reachable from here but also from the public picture page when logged as an administrator. Click on Edit or go next';
+$lang['first_contact_title15'] = 'The edition page of a picture';
+$lang['first_contact_stp15'] = 'On that page you can edit all the properties of a photo, for instance...';
+$lang['first_contact_title16'] = '';
+$lang['first_contact_stp16'] = 'here to add or remove the photo from albums. The link is virtual, no photos will be physically moved ever.';
+$lang['first_contact_title17'] = '';
+$lang['first_contact_stp17'] = 'and here to set the photo as a picture representative of an album. So you can set as a representative of a public album, a photo in a private album, which is ideal to set custom thumbnails for albums but the user won\'t see those pictures inside those albums. Like setting a portrait of someone as representative, for an album which contains photos of nature; it would be weird to see that photo of the man/woman among trees or animals.';
+$lang['first_contact_title18'] = 'Manage albums';
+$lang['first_contact_stp18'] = 'That previous example was just a small overview of tricks and how powerful Piwigo is. So I\'ve told about private albums, but how can we manage albums? Click On album->Manage or hit Next';
+$lang['first_contact_title19'] = 'Manage Albums';
+$lang['first_contact_stp19'] = 'Here are listed all the \'top\' albums, the ones at the root of your gallery. If you see an album with a dashed background, it\'s an real physical album from a FTP synchronisation, which can\'t be moved or deleted from here. The others albums are called virtual albums.';
+$lang['first_contact_stp19_b'] = 'All the albums are called \'virtual albums\'. Here are listed all the \'top\' albums, the ones at the root of your gallery.';
+$lang['first_contact_title20'] = 'Manage Albums';
+$lang['first_contact_stp20'] = 'When your mouse is hover a album, links and information appear. When you drag and drop an album -a rounded block-, you will change its position and then you can save or cancel your manual order.';
+$lang['first_contact_title21'] = 'Other Tabs';
+$lang['first_contact_stp21'] = 'The next tab is a page where you can move any virtual album.<br>The permalink tab is to set a particular url for an album, for technical reasons like to set a specific template or for just sending cool customized links.<br>But let\'s edit an album: click on Edit of a album';
+$lang['first_contact_title22'] = 'Album Edition Page';
+$lang['first_contact_stp22'] = 'Like for a picture, here you can edit the properties of an album';
+$lang['first_contact_title23'] = '';
+$lang['first_contact_stp23'] = 'Locking a album means only administrators will be able to see that album: it\'s usually used when an admin is managing the properties of an album or don\'t want to publish the album immediately';
+$lang['first_contact_title24'] = '';
+$lang['first_contact_stp24'] = 'Certainly, one of the most important page is the permission page of a private album. Click on the permission tab or click next';
+$lang['first_contact_title25'] = 'Album Permission';
+$lang['first_contact_stp25'] = 'As you can read in the Help of your Piwigo -link at the top right-, album permissions are set by groups and users. You can directly set private/public multiple albums using the Administration » Albums » Properties page.';
+$lang['first_contact_title26'] = '';
+$lang['first_contact_stp26'] = 'Here you can set the current album as private, then grant access to users and groups. By default, permissions are not recursive for sub albums, but upper-albums will be granted with the same permission in order to let the granted users browse to the album.';
+$lang['first_contact_title27'] = '';
+$lang['first_contact_stp27'] = 'Important fact: the webmasters and administrators are not omniscient when browsing the public part, but they can access to every album and photos on the admin part.';
+$lang['first_contact_title28'] = 'Configuration';
+$lang['first_contact_stp28'] = 'Now we will look at the options available to set Piwigo working your way. Click on Configuration->Options or just hit Next.';
+$lang['first_contact_title29'] = 'Configuration->Options->General';
+$lang['first_contact_stp29'] = 'Here, on that first page, you will set the essential and basic configuration of your gallery.';
+$lang['first_contact_title30'] = '';
+$lang['first_contact_stp30'] = 'Let\'s start by changing the tittle';
+$lang['first_contact_title31'] = '';
+$lang['first_contact_stp31'] = 'Then the banner, which will be displayed on top of every pages. As you can see, HTML tags are allowed here. You can also use the %gallery_title% tag to display the tittle you just typed above.';
+$lang['first_contact_title32'] = '';
+$lang['first_contact_stp32'] = 'Now save you changes';
+$lang['first_contact_title33'] = 'Guest settings';
+$lang['first_contact_stp33'] = 'Just a final word about the options, the \'Guest settings\' page is to set the preferences of unregistered visitors. Each time Piwigo refers to \'guest\' that means unregistered visitors.<br>Let\'s continue about Configuration: click on Configuration->Themes or just hit Next.';
+$lang['first_contact_title34'] = 'Themes';
+$lang['first_contact_stp34'] = 'Themes are one of the three way to customize your Piwigo, with Plugins and Templates. Themes installed are listed here.<br>More than one theme can be enabled: users can change their theme by choosing one among the one enabled here, if the option \'Allow user customization\' is checked on the Option page.';
+$lang['first_contact_title35'] = 'Themes';
+$lang['first_contact_stp35'] = 'Themes can also be set as Default, which means that\'s the theme for unregistered visitors (guests, you remember?) and any new registered user will be have this theme. But for any previously registered users, the theme won\'t change until you do it from the User Management page or you disable their theme: be careful, you might disturb your users by changing their whole display.';
+$lang['first_contact_title36'] = 'Themes';
+$lang['first_contact_stp36'] = 'Themes have a system of dependency: that\'s why some theme can\'t be deleted (a parent theme can\'t be deleted if a child theme is enabled) or others can\'t be enabled (a child theme need its parent theme). For instance, when you put you\'re mouse over a Delete link, if the theme can\'t be deleted, a information bubble will explain you why.';
+$lang['first_contact_title37'] = 'Themes';
+$lang['first_contact_stp37'] = 'To install new themes, you can directly download them from the tab \'Add a theme\'. Only the themes marked as compatible with your version of Piwigo are showed.<br>Let\'s discover the plugins now! Click on Plugin->Manage';
+$lang['first_contact_title38'] = 'Plugins';
+$lang['first_contact_stp38'] = 'Plugins are very easy ways to customize your Piwigo. They can do almost anything you can imagine from small text addition to complete features, like the Community plugin which allows non administrators users to upload without entering to the administration part.';
+$lang['first_contact_title39'] = 'Plugins';
+$lang['first_contact_stp39'] = 'On that first page, are listed the installed plugins. At the top, are listed the plugins activated, which are currently running. At the bottom, the plugins which are installed in the /plugins folder, but disabled. Deleting a plugin means that any trace of the plugin will be removed (files, options etc). For most of the plugins, disabling will keep the data registered by the plugins.';
+$lang['first_contact_title40'] = '';
+$lang['first_contact_stp40'] = 'Here it\'s me! Don\'t disable me now, but you can see you can Disable or Restore an activated plugin.';
+$lang['first_contact_title41'] = '';
+$lang['first_contact_stp41'] = 'You can see on the last tab all the plugins available for your version of Piwigo. Hundred of plugins are there!';
+$lang['first_contact_title42'] = 'Languages';
+$lang['first_contact_stp42'] = 'Piwigo is multilingual. By default, the language displayed by Piwigo change according to the language of the browser of the visitor. If the language of the visitor is not available, the language set by default is used.';
+$lang['first_contact_title43'] = 'It\'s been a great time';
+$lang['first_contact_stp43'] = 'This tour was quite long, but we only have seen a small part of how powerful Piwigo is. Everything has a end, this overview is finished.<br>You can discover much deeper the features of Piwigo by taking an other tour or reading our documentation, on the piwigo.org website.';
+?> \ No newline at end of file
diff --git a/plugins/TakeATour/language/fr_FR/description.txt b/plugins/TakeATour/language/fr_FR/description.txt
new file mode 100644
index 000000000..2992890d4
--- /dev/null
+++ b/plugins/TakeATour/language/fr_FR/description.txt
@@ -0,0 +1 @@
+Apprenez à utiliser votre Piwigo, avec ce plugin qui vous prendra par la main à travers ses 'visites' à thèmes \ No newline at end of file
diff --git a/plugins/TakeATour/language/fr_FR/index.php b/plugins/TakeATour/language/fr_FR/index.php
new file mode 100644
index 000000000..db1eae0d9
--- /dev/null
+++ b/plugins/TakeATour/language/fr_FR/index.php
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
diff --git a/plugins/TakeATour/language/fr_FR/plugin.lang.php b/plugins/TakeATour/language/fr_FR/plugin.lang.php
new file mode 100644
index 000000000..bf8763dcf
--- /dev/null
+++ b/plugins/TakeATour/language/fr_FR/plugin.lang.php
@@ -0,0 +1,96 @@
+<?php
+$lang['First Contact'] = 'Premier contact';
+$lang['Start the Tour'] = 'Commencez la visite';
+$lang['Visit your Piwigo!'] = 'Visiter votre Piwigo !';
+$lang['Take a tour and discover the features of your Piwigo gallery » Go to the available tours'] = 'Découvrez les fonctionnalités de votre galerie Piwigo » Voir les visites interactives disponibles';
+$lang['TAT_descrp'] = 'Welcome! Here are listed all the available tours to discover the features of your Piwigo gallery.<br>Launch a tour below, then follow the instructions. Click Next/Prev (or use the arrows of your keyboard) to navigate during a tour. During a tour, if you go to an other page of the administration, you will be redirected to the current page of the Tour. If you are stuck and can\'t end the tour, going to <em>Plugins » Take A Tour</em> will end the tour.';
+$lang['takeatour_configpage'] = 'Take A Tour » List of Tours';
+$lang['first_contact_descrp'] = 'Recommended for beginners, this tour introduce you Piwigo, its basic features. It will start by adding pictures, then manage them. The tour continues with album management and permissions, and ends on the customization using the configuration, the themes and the plugins.';
+$lang['first_contact_title1'] = 'Welcome in your Piwigo gallery';
+$lang['first_contact_stp1'] = 'Hello! I will be your guide to discover Piwigo. Please follow my instructions, and click Next (or use the arrows of your keyboard) to navigate. If you go to an other page of the administration, you will be redirected to the current page of the Tour. If you are stuck and can\'t end the tour, going to <em>Plugins » Take A Tour</em> will end the tour.<br>Let\'s start by adding pictures!';
+$lang['first_contact_title2'] = '';
+$lang['first_contact_stp2'] = 'The link is here. Click Next to continue';
+$lang['first_contact_title3'] = 'Add Photo Page';
+$lang['first_contact_stp3'] = 'This first tab is where you add photos directly from your browser. The other tabs are about the other ways to upload photos';
+$lang['first_contact_title4'] = 'Lets add photo!';
+$lang['first_contact_stp4'] = 'First choose an album; create one if there is no album yet.';
+$lang['first_contact_title5'] = '';
+$lang['first_contact_stp5'] = 'Then click the button to select photos to send from your computer';
+$lang['first_contact_title6'] = '';
+$lang['first_contact_stp6'] = 'You see that photos are being listed. Add at least 2 pictures and when you\'re ready click the button Start Upload';
+$lang['first_contact_title7'] = '';
+$lang['first_contact_stp7'] = 'Here a summary of your uploaded pictures. See that Piwigo has generated itself the thumbnails. You can know add more photos with the link at the bottom, edit the properties of a picture by clicking on it, or click to manage all the uploaded pictures in the Batch Manager...';
+$lang['first_contact_title8'] = '';
+$lang['first_contact_stp8'] = 'Let\'s edit them! Click on the link. If you don\'t see it click Prev to add at least 2 photos.';
+$lang['first_contact_title9'] = 'The Batch Manager';
+$lang['first_contact_stp9'] = 'You are know in the Batch Manager, where you can batch edit multiple pictures. Here the Caddy is set as a filter because we comes from the upload result page.';
+$lang['first_contact_title10'] = '';
+$lang['first_contact_stp10'] = 'Here is the link to directly access to your caddy: that/s a tool for administrators to easily add pictures to a set in order to edit them in the Batch Manager. You can add photos to the caddy from the public picture page when logged as an admin, or using the action \"Add to caddy\" on the Batch Manager';
+$lang['first_contact_title11'] = 'How to edit a photos';
+$lang['first_contact_stp11'] = 'So you can select from here one or more photos';
+$lang['first_contact_title12'] = '';
+$lang['first_contact_stp12'] = 'then edit them using and action. But for instance, you can\'t -for now- batch edit descriptions since they are mostly unique';
+$lang['first_contact_title13'] = '';
+$lang['first_contact_stp13'] = 'You can edit descriptions and more from the batch manager in unit mode. But for now, let\'s stay in the global mode';
+$lang['first_contact_title14'] = '';
+$lang['first_contact_stp14'] = 'We will see now the edition page of one picture. That page is reachable from here but also from the public picture page when logged as an administrator. Click on Edit or go next';
+$lang['first_contact_title15'] = 'The edition page of a picture';
+$lang['first_contact_stp15'] = 'On that page you can edit all the properties of a photo, for instance...';
+$lang['first_contact_title16'] = '';
+$lang['first_contact_stp16'] = 'here to add or remove the photo from albums. The link is virtual, no photos will be physically moved ever.';
+$lang['first_contact_title17'] = '';
+$lang['first_contact_stp17'] = 'and here to set the photo as a picture representative of an album. So you can set as a representative of a public album, a photo in a private album, which is ideal to set custom thumbnails for albums but the user won\'t see those pictures inside those albums. Like setting a portrait of someone as representative, for an album which contains photos of nature; it would be weird to see that photo of the man/woman among trees or animals.';
+$lang['first_contact_title18'] = 'Manage albums';
+$lang['first_contact_stp18'] = 'That previous example was just a small overview of tricks and how powerful Piwigo is. So I\'ve told about private albums, but how can we manage albums? Click On album->Manage or hit Next';
+$lang['first_contact_title19'] = 'Manage Albums';
+$lang['first_contact_stp19'] = 'Here are listed all the \'top\' albums, the ones at the root of your gallery. If you see an album with a dashed background, it\'s an real physical album from a FTP synchronisation, which can\'t be moved or deleted from here. The others albums are called virtual albums.';
+$lang['first_contact_stp19_b'] = 'All the albums are called \'virtual albums\'. Here are listed all the \'top\' albums, the ones at the root of your gallery.';
+$lang['first_contact_title20'] = 'Manage Albums';
+$lang['first_contact_stp20'] = 'When your mouse is hover a album, links and information appear. When you drag and drop an album -a rounded block-, you will change its position and then you can save or cancel your manual order.';
+$lang['first_contact_title21'] = 'Other Tabs';
+$lang['first_contact_stp21'] = 'The next tab is a page where you can move any virtual album.<br>The permalink tab is to set a particular url for an album, for technical reasons like to set a specific template or for just sending cool customized links.<br>But let\'s edit an album: click on Edit of a album';
+$lang['first_contact_title22'] = 'Album Edition Page';
+$lang['first_contact_stp22'] = 'Like for a picture, here you can edit the properties of an album';
+$lang['first_contact_title23'] = '';
+$lang['first_contact_stp23'] = 'Locking a album means only administrators will be able to see that album: it\'s usually used when an admin is managing the properties of an album or don\'t want to publish the album immediately';
+$lang['first_contact_title24'] = '';
+$lang['first_contact_stp24'] = 'Certainly, one of the most important page is the permission page of a private album. Click on the permission tab or click next';
+$lang['first_contact_title25'] = 'Album Permission';
+$lang['first_contact_stp25'] = 'As you can read in the Help of your Piwigo -link at the top right-, album permissions are set by groups and users. You can directly set private/public multiple albums using the Administration » Albums » Properties page.';
+$lang['first_contact_title26'] = '';
+$lang['first_contact_stp26'] = 'Here you can set the current album as private, then grant access to users and groups. By default, permissions are not recursive for sub albums, but upper-albums will be granted with the same permission in order to let the granted users browse to the album.';
+$lang['first_contact_title27'] = '';
+$lang['first_contact_stp27'] = 'Important fact: the webmasters and administrators are not omniscient when browsing the public part, but they can access to every album and photos on the admin part.';
+$lang['first_contact_title28'] = 'Configuration';
+$lang['first_contact_stp28'] = 'Now we will look at the options available to set Piwigo working your way. Click on Configuration->Options or just hit Next.';
+$lang['first_contact_title29'] = 'Configuration->Options->General';
+$lang['first_contact_stp29'] = 'Here, on that first page, you will set the essential and basic configuration of your gallery.';
+$lang['first_contact_title30'] = '';
+$lang['first_contact_stp30'] = 'Let\'s start by changing the tittle';
+$lang['first_contact_title31'] = '';
+$lang['first_contact_stp31'] = 'Then the banner, which will be displayed on top of every pages. As you can see, HTML tags are allowed here. You can also use the %gallery_title% tag to display the tittle you just typed above.';
+$lang['first_contact_title32'] = '';
+$lang['first_contact_stp32'] = 'Now save you changes';
+$lang['first_contact_title33'] = 'Guest settings';
+$lang['first_contact_stp33'] = 'Just a final word about the options, the \'Guest settings\' page is to set the preferences of unregistered visitors. Each time Piwigo refers to \'guest\' that means unregistered visitors.<br>Let\'s continue about Configuration: click on Configuration->Themes or just hit Next.';
+$lang['first_contact_title34'] = 'Themes';
+$lang['first_contact_stp34'] = 'Themes are one of the three way to customize your Piwigo, with Plugins and Templates. Themes installed are listed here.<br>More than one theme can be enabled: users can change their theme by choosing one among the one enabled here, if the option \'Allow user customization\' is checked on the Option page.';
+$lang['first_contact_title35'] = 'Themes';
+$lang['first_contact_stp35'] = 'Themes can also be set as Default, which means that\'s the theme for unregistered visitors (guests, you remember?) and any new registered user will be have this theme. But for any previously registered users, the theme won\'t change until you do it from the User Management page or you disable their theme: be careful, you might disturb your users by changing their whole display.';
+$lang['first_contact_title36'] = 'Themes';
+$lang['first_contact_stp36'] = 'Themes have a system of dependency: that\'s why some theme can\'t be deleted (a parent theme can\'t be deleted if a child theme is enabled) or others can\'t be enabled (a child theme need its parent theme). For instance, when you put you\'re mouse over a Delete link, if the theme can\'t be deleted, a information bubble will explain you why.';
+$lang['first_contact_title37'] = 'Themes';
+$lang['first_contact_stp37'] = 'To install new themes, you can directly download them from the tab \'Add a theme\'. Only the themes marked as compatible with your version of Piwigo are showed.<br>Let\'s discover the plugins now! Click on Plugin->Manage';
+$lang['first_contact_title38'] = 'Plugins';
+$lang['first_contact_stp38'] = 'Plugins are very easy ways to customize your Piwigo. They can do almost anything you can imagine from small text addition to complete features, like the Community plugin which allows non administrators users to upload without entering to the administration part.';
+$lang['first_contact_title39'] = 'Plugins';
+$lang['first_contact_stp39'] = 'On that first page, are listed the installed plugins. At the top, are listed the plugins activated, which are currently running. At the bottom, the plugins which are installed in the /plugins folder, but disabled. Deleting a plugin means that any trace of the plugin will be removed (files, options etc). For most of the plugins, disabling will keep the data registered by the plugins.';
+$lang['first_contact_title40'] = '';
+$lang['first_contact_stp40'] = 'Here it\'s me! Don\'t disable me now, but you can see you can Disable or Restore an activated plugin.';
+$lang['first_contact_title41'] = '';
+$lang['first_contact_stp41'] = 'You can see on the last tab all the plugins available for your version of Piwigo. Hundred of plugins are there!';
+$lang['first_contact_title42'] = 'Languages';
+$lang['first_contact_stp42'] = 'Piwigo is multilingual. By default, the language displayed by Piwigo change according to the language of the browser of the visitor. If the language of the visitor is not available, the language set by default is used.';
+$lang['first_contact_title43'] = 'It\'s been a great time';
+$lang['first_contact_stp43'] = 'This tour was quite long, but we only have seen a small part of how powerful Piwigo is. Everything has a end, this overview is finished.<br>You can discover much deeper the features of Piwigo by taking an other tour or reading our documentation, on the piwigo.org website.';
+?> \ No newline at end of file
diff --git a/plugins/TakeATour/main.inc.php b/plugins/TakeATour/main.inc.php
new file mode 100644
index 000000000..46466c4c3
--- /dev/null
+++ b/plugins/TakeATour/main.inc.php
@@ -0,0 +1,133 @@
+<?php
+/*
+Plugin Name: Take A Tour of Your Piwigo
+Version: 1.0
+Description: Plugin Personnel
+Plugin URI: http://piwigo.org
+Author:Piwigo Team
+Author URI:
+*/
+if (!defined('PHPWG_ROOT_PATH'))
+{
+ die('Hacking attempt!');
+}
+
+$avalaible_tour = array('first_contact', 'privacy', 'picture_protection');
+
+if ( isset($_POST['submited_tour']) and in_array($_POST['submited_tour'], $avalaible_tour) and defined('IN_ADMIN') and IN_ADMIN )
+{
+ check_pwg_token();
+ pwg_set_session_var('tour_to_launch', $_POST['submited_tour']);
+ global $TAT_restart;
+ $TAT_restart=true;
+}
+elseif ( isset($_GET['tour_ended']) and in_array($_GET['tour_ended'], $avalaible_tour) and defined('IN_ADMIN') and IN_ADMIN )
+{
+ pwg_unset_session_var('tour_to_launch');
+}
+
+if (pwg_get_session_var('tour_to_launch') and defined('IN_ADMIN') and IN_ADMIN and isset($_GET['page']) and $_GET['page']=="plugin-TakeATour" )
+{
+ pwg_unset_session_var('tour_to_launch');
+}
+elseif ( pwg_get_session_var('tour_to_launch') and defined('IN_ADMIN') and IN_ADMIN)
+{
+ add_event_handler('init', 'TAT_add_js_css');
+ include('tours/'.pwg_get_session_var('tour_to_launch').'/config.inc.php');
+}
+
+function TAT_add_js_css()
+{
+ global $template, $TAT_restart;
+ $tour_to_launch=pwg_get_session_var('tour_to_launch');
+ load_language('plugin.lang', PHPWG_PLUGINS_PATH .'TakeATour/');
+ load_language('lang', PHPWG_ROOT_PATH.PWG_LOCAL_DIR, array('no_fallback'=>true, 'local'=>true) );
+ $template->set_filename('TAT_js_css', PHPWG_PLUGINS_PATH.'TakeATour/tpl/js_css.tpl');
+ $template->parse('TAT_js_css');//http://piwigo.org/forum/viewtopic.php?id=23248
+ if (isset($TAT_restart) and $TAT_restart)
+ {
+ $TAT_restart=false;
+ $template->assign('TAT_restart',true);
+ }
+ $tat_path=str_replace(basename($_SERVER['SCRIPT_NAME']),'', $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME']);
+ $template->assign('TAT_path', $tat_path);
+ @include('tours/'.$tour_to_launch.'/config_preparse.inc.php');
+ $template->set_filename('TAT_tour_tpl', PHPWG_PLUGINS_PATH.'TakeATour/tours/'.$tour_to_launch.'/tour.tpl');
+ $template->parse('TAT_tour_tpl');
+}
+
+
+add_event_handler('loc_end_help','TAT_help');
+function TAT_help()
+{
+ global $template;
+ load_language('plugin.lang', PHPWG_PLUGINS_PATH .'TakeATour/');
+ $template->set_prefilter('help', 'TAT_help_prefilter');
+}
+function TAT_help_prefilter($content, &$smarty)
+{
+
+ $search = '<div id="helpContent">';
+ $replacement = '<div id="helpContent">
+<fieldset>
+<legend>{\'Visit your Piwigo!\'|@translate}</legend>
+<p class="nextStepLink"><a href="admin.php?page=plugin-TakeATour">{\'Take a tour and discover the features of your Piwigo gallery » Go to the available tours\'|@translate}</a></p>
+</fieldset>';
+ return(str_replace($search, $replacement, $content));
+
+}
+add_event_handler('loc_end_no_photo_yet','TAT_no_photo_yet');
+function TAT_no_photo_yet()
+{
+ global $template;
+ load_language('plugin.lang', PHPWG_PLUGINS_PATH .'TakeATour/');
+ $template->set_prefilter('no_photo_yet', 'TAT_no_photo_yet_prefilter');
+ $template->assign(
+ array(
+ 'F_ACTION' => get_root_url().'admin.php',
+ 'pwg_token' => get_pwg_token()
+ )
+ );
+}
+function TAT_no_photo_yet_prefilter($content, &$smarty)
+{
+
+ $search = '<div class="bigButton"><a href="{$next_step_url}">{\'I want to add photos\'|@translate}</a></div>';
+ $replacement = '<form style="text-align:center" action="{$F_ACTION}" method="post">
+ <input type="hidden" name="submited_tour" value="first_contact">
+ <input type="hidden" name="pwg_token" value="{$pwg_token}">
+ <input type="submit" name="button2" id="button2" value="{\'I want to discover my gallery and add photos\'|@translate}">
+</form>
+<div class="bigButton"><a href="{$next_step_url}">{\'I want to add photos\'|@translate}</a></div>';
+ $content=str_replace($search, $replacement, $content);
+ $search = '</style>';
+ $replacement = '
+form input[type="submit"] {
+ font-size: 25px;
+ letter-spacing: 2px;
+ margin: 0 5px;
+ padding: 20px;
+ border:none;
+ background-color:#666666;
+ color:#fff;
+ cursor:pointer;
+}
+form input[type="submit"]:hover {
+ background-color:#ff7700;
+ color:white;
+}
+</style>';
+ return(str_replace($search, $replacement, $content));
+}
+
+add_event_handler('get_admin_plugin_menu_links', 'TAT_admin_menu' );
+function TAT_admin_menu($menu)
+{
+ array_push($menu, array(
+ 'NAME' => 'Take a Tour',
+ 'URL' => get_root_url().'admin.php?page=plugin-TakeATour'
+ )
+ );
+ return $menu;
+}
+?> \ No newline at end of file
diff --git a/plugins/TakeATour/tours/first_contact/config.inc.php b/plugins/TakeATour/tours/first_contact/config.inc.php
new file mode 100644
index 000000000..74bad9eda
--- /dev/null
+++ b/plugins/TakeATour/tours/first_contact/config.inc.php
@@ -0,0 +1,71 @@
+<?php
+if ( defined('IN_ADMIN') and IN_ADMIN )
+{
+/* first contact */
+add_event_handler('loc_end_element_set_global', 'TAT_FC_14');
+add_event_handler('loc_end_picture_modify', 'TAT_FC_16');
+add_event_handler('loc_end_picture_modify', 'TAT_FC_17');
+add_event_handler('loc_end_cat_modify', 'TAT_FC_23');
+add_event_handler('loc_end_themes_installed', 'TAT_FC_35');
+}
+
+function TAT_FC_14()
+{
+ global $template;
+ $template->set_prefilter('batch_manager_global', 'TAT_FC_14_prefilter');
+}
+function TAT_FC_14_prefilter ($content, &$smarty)
+{
+ $search = '<span class="wrap2';
+ $replacement = '{counter print=false assign=TAT_FC_14}<span {if $TAT_FC_14==1}id="TAT_FC_14"{/if} class="wrap2';
+ $content = str_replace($search, $replacement, $content);
+ $search = 'target="_blank">{\'Edit\'';
+ $replacement = '>{\'Edit\'';
+ return str_replace($search, $replacement, $content);
+}
+function TAT_FC_16()
+{
+ global $template;
+ $template->set_prefilter('picture_modify', 'TAT_FC_16_prefilter');
+}
+function TAT_FC_16_prefilter ($content, &$smarty)
+{
+ $search = '<strong>{\'Linked albums\'|@translate}</strong>';
+ $replacement = '<span id="TAT_FC_16"><strong>{\'Linked albums\'|@translate}</strong></span>';
+ return str_replace($search, $replacement, $content);
+}
+function TAT_FC_17()
+{
+ global $template;
+ $template->set_prefilter('picture_modify', 'TAT_FC_17_prefilter');
+}
+function TAT_FC_17_prefilter ($content, &$smarty)
+{
+ $search = '<strong>{\'Representation of albums\'|@translate}</strong>';
+ $replacement = '<span id="TAT_FC_17"><strong>{\'Representation of albums\'|@translate}</strong></span>';
+ return str_replace($search, $replacement, $content);
+}
+function TAT_FC_23()
+{
+ global $template;
+ $template->set_prefilter('album_properties', 'TAT_FC_23_prefilter');
+}
+function TAT_FC_23_prefilter ($content, &$smarty)
+{
+ $search = '<strong>{\'Lock\'|@translate}</strong>';
+ $replacement = '<span id="TAT_FC_23"><strong>{\'Lock\'|@translate}</strong></span>';
+ return str_replace($search, $replacement, $content);
+}
+function TAT_FC_35()
+{
+ global $template;
+ $template->set_prefilter('themes', 'TAT_FC_35_prefilter');
+}
+function TAT_FC_35_prefilter ($content, &$smarty)
+{
+ $search = '<a href="{$set_default_baseurl}{$theme.ID}" class="tiptip"';
+ $replacement = '{counter print=false assign=TAT_FC_35}<a href="{$set_default_baseurl}{$theme.ID}" class="tiptip" {if $TAT_FC_35==1}id="TAT_FC_35"{/if}';
+ return str_replace($search, $replacement, $content);
+}
+
+?> \ No newline at end of file
diff --git a/plugins/TakeATour/tours/first_contact/config_preparse.inc.php b/plugins/TakeATour/tours/first_contact/config_preparse.inc.php
new file mode 100644
index 000000000..711dfe349
--- /dev/null
+++ b/plugins/TakeATour/tours/first_contact/config_preparse.inc.php
@@ -0,0 +1,59 @@
+<?php
+ //picture id
+ if (isset($_GET['page']) and preg_match('/^photo-(\d+)(?:-(.*))?$/', $_GET['page'], $matches))
+ {
+ $_GET['image_id'] = $matches[1];
+ }
+ check_input_parameter('image_id', $_GET, false, PATTERN_ID);
+ if (isset($_GET['image_id']) and pwg_get_session_var('TAT_image_id')==null)
+ {
+ $template->assign('TAT_image_id', $_GET['image_id']);
+ pwg_set_session_var('TAT_image_id', $_GET['image_id']);
+ }
+ elseif (is_numeric(pwg_get_session_var('TAT_image_id')))
+ {
+ $template->assign('TAT_image_id', pwg_get_session_var('TAT_image_id'));
+ }
+ else
+ {
+ $query = '
+ SELECT id
+ FROM '.IMAGES_TABLE.'
+ ORDER BY RAND()
+ LIMIT 1
+ ;';
+ $row = pwg_db_fetch_assoc(pwg_query($query));
+ $template->assign('TAT_image_id', $row['id']);
+ }
+ //album id
+ if (isset($_GET['page']) and preg_match('/^album-(\d+)(?:-(.*))?$/', $_GET['page'], $matches))
+ {
+ $_GET['cat_id'] = $matches[1];
+ }
+ check_input_parameter('cat_id', $_GET, false, PATTERN_ID);
+ if (isset($_GET['cat_id']) and pwg_get_session_var('TAT_cat_id')==null)
+ {
+ $template->assign('TAT_cat_id', $_GET['cat_id']);
+ pwg_set_session_var('TAT_cat_id', $_GET['cat_id']);
+ }
+ elseif (is_numeric(pwg_get_session_var('TAT_cat_id')))
+ {
+ $template->assign('TAT_cat_id', pwg_get_session_var('TAT_cat_id'));
+ }
+ else
+ {
+ $query = '
+ SELECT id
+ FROM '.CATEGORIES_TABLE.'
+ ORDER BY RAND()
+ LIMIT 1
+ ;';
+ $row = pwg_db_fetch_assoc(pwg_query($query));
+ $template->assign('TAT_cat_id', $row['id']);
+ }
+ global $conf;
+ if ( isset($conf['enable_synchronization']) )
+ {
+ $template->assign('TAT_FTP', $conf['enable_synchronization']);
+ }
+?> \ No newline at end of file
diff --git a/plugins/TakeATour/tours/first_contact/tour.tpl b/plugins/TakeATour/tours/first_contact/tour.tpl
new file mode 100644
index 000000000..885dfe212
--- /dev/null
+++ b/plugins/TakeATour/tours/first_contact/tour.tpl
@@ -0,0 +1,349 @@
+{footer_script require='jquery.bootstrap-tour'}{literal}
+
+var tour = new Tour({
+ name: "first_contact",
+ orphan: true,
+ onEnd: function (tour) {window.location = "admin.php?page=plugin-TakeATour&tour_ended=first_contact";},
+});
+{/literal}{if $TAT_restart}tour.restart();{/if}{literal}
+
+tour.addSteps([
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php",
+ title: "{/literal}{'first_contact_title1'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp1'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php",
+ placement: "right",
+ element: ".icon-plus-circled",
+ reflex:true,
+ title: "{/literal}{'first_contact_title2'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp2'|@translate}{literal}",
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=photos_add",
+ placement: "bottom",
+ element: ".selected_tab",
+ title: "{/literal}{'first_contact_title3'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp3'|@translate}{literal}",
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=photos_add",
+ placement: "left",
+ element: "#albumSelection",
+ title: "{/literal}{'first_contact_title4'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp4'|@translate}{literal}"
+ },
+ {//5
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=photos_add",
+ placement: "top",
+ element: "#uploadify",
+ title: "{/literal}{'first_contact_title5'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp5'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=photos_add/,
+ redirect:function (tour) {window.location = "admin.php?page=photos_add";},
+ placement: "left",
+ element: "#fileQueue",
+ title: "{/literal}{'first_contact_title6'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp6'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=photos_add/,
+ redirect:function (tour) {window.location = "admin.php?page=photos_add";},
+ placement: "top",
+ element: "#photosAddContent legend",
+ title: "{/literal}{'first_contact_title7'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp7'|@translate}{literal}",
+ prev:4
+ },
+ {
+ path: /admin\.php\?page=photos_add/,
+ redirect:function (tour) {window.location = "admin.php?page=photos_add";},
+ placement: "bottom",
+ element: "#batchLink",
+ reflex:true,
+ title: "{/literal}{'first_contact_title8'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp8'|@translate}{literal}",
+ prev:4
+ },
+ {
+ path: /admin\.php\?page=(photos_add|batch_manager&filter=prefilter-last_import|prefilter-caddie)/,
+ redirect:function (tour) {window.location = "admin.php?page=batch_manager&filter=prefilter-last_import";},
+ placement: "top",
+ element: "",
+ title: "{/literal}{'first_contact_title9'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp9'|@translate}{literal}"
+ },
+ {//10
+ path: /admin\.php\?page=batch_manager&filter=(prefilter-caddie|prefilter-last_import)/,
+ redirect:function (tour) {window.location = "admin.php?page=batch_manager&filter=prefilter-last_import";},
+ placement: "right",
+ element: ".icon-flag",
+ title: "{/literal}{'first_contact_title10'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp10'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=batch_manager&filter=(prefilter-caddie|prefilter-last_import)/,
+ redirect:function (tour) {window.location = "admin.php?page=batch_manager&filter=prefilter-last_import";},
+ placement: "left",
+ element: "#checkActions",
+ title: "{/literal}{'first_contact_title11'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp11'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=batch_manager&filter=(prefilter-caddie|prefilter-last_import)/,
+ redirect:function (tour) {window.location = "admin.php?page=batch_manager&filter=prefilter-last_import";},
+ placement: "top",
+ element: "#action",
+ title: "{/literal}{'first_contact_title12'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp12'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=batch_manager&filter=(prefilter-caddie|prefilter-last_import)/,
+ redirect:function (tour) {window.location = "admin.php?page=batch_manager&filter=prefilter-last_import";},
+ placement: "bottom",
+ element: "#tabsheet .normal_tab",
+ title: "{/literal}{'first_contact_title13'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp13'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=batch_manager&filter=(prefilter-caddie|prefilter-last_import)/,
+ redirect:function (tour) {window.location = "admin.php?page=batch_manager&filter=prefilter-last_import";},
+ placement: "top",
+ element: "#TAT_FC_14",
+ reflex:true,
+ title: "{/literal}{'first_contact_title14'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp14'|@translate}{literal}",
+ onNext:function (tour) {window.location = "admin.php?page=photo-{/literal}{$TAT_image_id}{literal}";}
+ },
+ {//15
+ path: /admin\.php\?page=photo-/,
+ redirect:function (tour) {window.location = "admin.php?page=photo-{/literal}{$TAT_image_id}{literal}";},
+ placement: "bottom",
+ element: ".selected_tab",
+ title: "{/literal}{'first_contact_title15'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp15'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=photo-/,
+ redirect:function (tour) {window.location = "admin.php?page=photo-{/literal}{$TAT_image_id}{literal}";},
+ placement: "top",
+ element: "#TAT_FC_16",
+ title: "{/literal}{'first_contact_title16'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp16'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=photo-/,
+ redirect:function (tour) {window.location = "admin.php?page=photo-{/literal}{$TAT_image_id}{literal}";},
+ placement: "top",
+ element: "#TAT_FC_17",
+ title: "{/literal}{'first_contact_title17'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp17'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=photo-/,
+ redirect:function (tour) {window.location = "admin.php?page=photo-{/literal}{$TAT_image_id}{literal}";},
+ placement: "top",
+ title: "{/literal}{'first_contact_title18'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp18'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=cat_list",
+ placement: "left",
+ element: "#content",
+ title: "{/literal}{'first_contact_title19'|@translate}{literal}",
+ content: "{/literal}{if $TAT_FTP}{'first_contact_stp19'|@translate}{else}{'first_contact_stp19_b'|@translate}{/if}{literal}",
+ onPrev: function (tour) {window.location = "admin.php?page=photo-{/literal}{$TAT_image_id}{literal}";},
+
+ },
+ {//20
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=cat_list",
+ placement: "top",
+ element: "#categoryOrdering",
+ title: "{/literal}{'first_contact_title20'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp20'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=cat_list",
+ placement: "left",
+ element: "#tabsheet:first-child",
+ title: "{/literal}{'first_contact_title21'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp21'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=album-/,
+ redirect:function (tour) {window.location = "admin.php?page=album-{/literal}{$TAT_cat_id}{literal}";},
+ placement: "top",
+ element: ".selected_tab",
+ title: "{/literal}{'first_contact_title22'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp22'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=album-/,
+ redirect:function (tour) {window.location = "admin.php?page=album-{/literal}{$TAT_cat_id}{literal}";},
+ placement: "top",
+ element: "#TAT_FC_23",
+ title: "{/literal}{'first_contact_title23'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp23'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=album-/,
+ redirect:function (tour) {window.location = "admin.php?page=album-{/literal}{$TAT_cat_id}{literal}";},
+ placement: "bottom",
+ element: ".tabsheet",
+ title: "{/literal}{'first_contact_title24'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp24'|@translate}{literal}"
+ },
+ {//25
+ path: /admin\.php\?page=album-[0-9]+-permissions/,
+ redirect:function (tour) {window.location = "admin.php?page=album-{/literal}{$TAT_cat_id}{literal}-permissions";},
+ placement: "left",
+ element: "#content",
+ title: "{/literal}{'first_contact_title25'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp25'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=album-[0-9]+-permissions/,
+ redirect:function (tour) {window.location = "admin.php?page=album-{/literal}{$TAT_cat_id}{literal}-permissions";},
+ placement: "top",
+ element: "#selectStatus",
+ title: "{/literal}{'first_contact_title26'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp26'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=album-[0-9]+-permissions/,
+ redirect:function (tour) {window.location = "admin.php?page=album-{/literal}{$TAT_cat_id}{literal}-permissions";},
+ placement: "top",
+ element: "#selectStatus",
+ title: "{/literal}{'first_contact_title27'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp27'|@translate}{literal}"
+ },
+ {
+ path: /admin\.php\?page=album-[0-9]+-permissions/,
+ redirect:function (tour) {window.location = "admin.php?page=album-{/literal}{$TAT_cat_id}{literal}-permissions";},
+ placement: "top",
+ title: "{/literal}{'first_contact_title28'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp28'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=configuration",
+ placement: "top",
+ element: "",
+ title: "{/literal}{'first_contact_title29'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp29'|@translate}{literal}"
+ },
+ {//30
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=configuration",
+ placement: "right",
+ element: "#gallery_title",
+ title: "{/literal}{'first_contact_title30'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp30'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=configuration",
+ placement: "right",
+ element: "#page_banner",
+ title: "{/literal}{'first_contact_title31'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp31'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=configuration",
+ reflex: true,
+ placement: "top",
+ element: ".formButtons input",
+ title: "{/literal}{'first_contact_title32'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp32'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=configuration",
+ placement: "top",
+ title: "{/literal}{'first_contact_stp33'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp33'|@translate}{literal}",
+ prev:30
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=themes",
+ placement: "top",
+ element: "",
+ title: "{/literal}{'first_contact_title34'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp34'|@translate}{literal}"
+ },
+ {//35
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=themes",
+ placement: "top",
+ element: "#TAT_FC_35",
+ title: "{/literal}{'first_contact_title35'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp35'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=themes",
+ placement: "top",
+ element: "",
+ title: "{/literal}{'first_contact_title36'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp36'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=themes",
+ placement: "right",
+ element: ".tabsheet",
+ title: "{/literal}{'first_contact_title37'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp37'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=plugins",
+ placement: "left",
+ element: "",
+ title: "{/literal}{'first_contact_title38'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp38'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=plugins",
+ placement: "left",
+ element: "#content",
+ title: "{/literal}{'first_contact_title39'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp39'|@translate}{literal}"
+ },
+ {//40
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=plugins",
+ placement: "bottom",
+ element: "#TakeATour",
+ title: "{/literal}{'first_contact_title40'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp40'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=plugins",
+ placement: "right",
+ element: ".tabsheet",
+ title: "{/literal}{'first_contact_title41'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp41'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=languages",
+ title: "{/literal}{'first_contact_title42'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp42'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=plugin-TakeATour",
+ placement: "top",
+ element: "",
+ title: "{/literal}{'first_contact_title43'|@translate}{literal}",
+ content: "{/literal}{'first_contact_stp43'|@translate}{literal}"
+ }
+]);
+
+// Initialize the tour
+tour.init();
+
+// Start the tour
+tour.start();
+
+jQuery( "input[class='submit']" ).click(function() {
+ if (tour.getCurrentStep()==5)
+ {
+ tour.goTo(6);
+ }
+});
+{/literal}{/footer_script} \ No newline at end of file
diff --git a/plugins/TakeATour/tours/scaling/scaling.tpl b/plugins/TakeATour/tours/scaling/scaling.tpl
new file mode 100644
index 000000000..b658e13df
--- /dev/null
+++ b/plugins/TakeATour/tours/scaling/scaling.tpl
@@ -0,0 +1,89 @@
+{footer_script require='jquery.bootstrap-tour'}{literal}
+// Instance the tour
+var tour = new Tour({
+ name: "scaling",
+ orphan: true,
+ onEnd: function (tour) {window.location = "admin.php?page=plugin-TakeATour&tour_ended=scaling";},
+});
+{/literal}{if $TAT_restart}tour.restart();{/if}{literal}
+// Add your steps. Not too many, you don't really want to get your users sleepy
+tour.addSteps([
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php",
+ title: "{/literal}{'Welcome on the /'Scaling/' Tour'|@translate}{literal}",
+ content: "{/literal}{'This tour will show you how to configure your Piwigo according to your server resources. This tour is for beginners and for advanced user, so you can skip technical steps if you want.'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php",
+ title: "{/literal}{'Servers'|@translate}{literal}",
+ content: "{/literal}{'On free hosting and shared hosting, multiple websites are on the same physical server, so resources are shared. So your hosting provider may restrictions for CPU and memory consumptions.<br>For dedicated servers, you will be able to adjust the resource consumption of your Piwigo.'|@translate}{literal}"
+ },
+
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.phpSIZE",
+ content: "{/literal}{'The main resource consumption is the generation of resized pictures. To lower that, you can disable some size. Size are for plugins and themes to display the best size according to the user screen, and for the users who can prefer lower resolution photos (bandwidth etc)'|@translate}{literal}"
+ }
+
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php?page=batch_manager",
+ title: "{/literal}{'Resized picture generation'|@translate}{literal}",
+ content: "{/literal}{'Piwigo generates on the demand and on the fly the resized pictures: so the first user browsing the gallery after an upload will trigger the generation of the thumbnails, for instance. At that moment the server ressources might be too hight for some hosting. Then those pictures generated are stored, so no further picture generation will be done again.<br>After a big upload, you might prefer to trigger the generation of those resized pictures yourself: instead of having a small long term resource consumption; the server will have a short peak of computation. According to your hosting, it might be better to generate once, quickly. Choose the /"Generate/" action in the Batch Manager to do so.<br>For advanced users, and if you have a FTP access, you can upload resized pictures
+generated on your computer in the _data/i folder: be careful when naming the files.'|@translate}{literal}"
+ },
+
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.php",
+ title: "{/literal}{'Graphic library'|@translate}{literal}",
+ content: "{/literal}{''|@translate}{literal}"
+ },
+
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.phpHISTORY",
+ title: "{/literal}{'History'|@translate}{literal}",
+ content: "{/literal}{'Some hosting has a limitation for how much data can be stored in the database. The history data can become huge if you record guest visits and don/'t purge the history. So you can disable it or disable for guests, but check before the available plugins!<br>So if you get an error about a "piwigo_history" "table", it/'s probably about a needed purge of the history.'|@translate}{literal}"
+ },
+
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.phpPLUGINS",
+ title: "{/literal}{'Local Configuration'|@translate}{literal}",
+ content: "{/literal}{'Please enable the Local Files Editor for the next step.'|@translate}{literal}"
+ },
+
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.phpLFE",
+ title: "{/literal}{'Local Configuration'|@translate}{literal}",
+ content: "{/literal}{'Piwigo has a Local Configuration, which is in fact a list of variables not present in the Graphic Interface. The Default Configuration file has every variables available in it, the default values for them and an explicative text for each of them.<br>To set your own values, use that page which is a text editor for Local Configuration file: the values in the local config override the default config.<br>The workflow is quite simple...|@translate}{literal}"
+ },
+
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.phpLFE",
+ placement: "left",
+ element: "LIEN",
+ title: "{/literal}{'Servers'|@translate}{literal}",
+ content: "{/literal}{'Browse the default config, and when you have found some interesting variable, copy/paste here and change the value.'|@translate}{literal}"
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.phpLFE",
+ title: "{/literal}{'Local Configuration'|@translate}{literal}",
+ content: "{/literal}{'Some variable you could change for scaling up or down your Piwigo:<ul><li>$conf['template_compile_check'] : This tells Smarty whether to check for recompiling or not. Recompiling does not need to happen unless a template is changed. false results in better performance.</li><li>$conf['compiled_template_cache_language'] : if true, some language strings are replaced during template compilation (instead of template output). This results in better performance. However any change in the language file will not be propagated until you purge the compiled templates from the admin / maintenance menu</li><li>$conf['template_combine_files'] : if true -defaukt value-, it activates merging of javascript / css files in order to reduce a lot the loading of the server due to multiple requests.</li><li>$conf['max_requests'] : maximum Ajax requests at once, for thumbnails on-the-fly generation. Increase that number (3 by default) if your server can handle the resource consumption due to the generation of the thumbnails, and if you want a better user experience.</li></ul>'|@translate}{literal}",
+ },
+ {
+ path: "{/literal}{$TAT_path}{literal}admin.phpLFE",
+ title: "{/literal}{'Finished'|@translate}{literal}",
+ content: "{/literal}{'There are other variables you might tune, some features you could disable (ratings, comments etc), custom theme you could do to remove some information but the thing is Piwigo is already flexible and powerful. The only critical point which might be raised, is the generation of resized pictures: go back in this tour to remember what I told you.<br>Now you can end this tour, and I hope to see you soon.'|@translate}{literal}"
+ }
+]);
+
+// Initialize the tour
+tour.init();
+
+// Start the tour
+tour.start();
+
+jQuery( "input[class='submit']" ).click(function() {
+ if (tour.getCurrentStep()==5)
+ {
+ tour.goTo(6);
+ }
+});
+{/literal}{/footer_script} \ No newline at end of file
diff --git a/plugins/TakeATour/tpl/admin.tpl b/plugins/TakeATour/tpl/admin.tpl
new file mode 100644
index 000000000..ae6c7a199
--- /dev/null
+++ b/plugins/TakeATour/tpl/admin.tpl
@@ -0,0 +1,17 @@
+<div class="titrePage">
+ <h2>{'takeatour_configpage'|@translate}</h2>
+</div>
+<div id="helpContent">
+ <p>{'TAT_descrp'|@translate}</p>
+ {if !isset($TAT_tour_ignored) or (isset($TAT_tour_ignored) and in_array(first_contact, $TAT_tour_ignored))}
+ <fieldset>
+ <legend>{'First Contact'|@translate}</legend>
+ <div class="TAT_description">{'first_contact_descrp'|@translate}</div>
+ <form action="{$F_ACTION}" method="post">
+ <input type="hidden" name="submited_tour" value="first_contact">
+ <input type="hidden" name="pwg_token" value="{$pwg_token}">
+ <input type="submit" name="button2" id="button2" value="{'Start the Tour'|@translate}">
+ </form>
+ </fieldset>
+ {/if}
+</div> \ No newline at end of file
diff --git a/plugins/TakeATour/tpl/js_css.tpl b/plugins/TakeATour/tpl/js_css.tpl
new file mode 100644
index 000000000..240263ad5
--- /dev/null
+++ b/plugins/TakeATour/tpl/js_css.tpl
@@ -0,0 +1,3 @@
+{combine_script id='jquery.bootstrap-tour' load='header' require='jquery' path='plugins/TakeATour/js/custom-bootstrap-tour-standalone.js'}
+{combine_css path="plugins/TakeATour/css/bootstrap-essential.css"}
+{combine_css path="plugins/TakeATour/css/bootstrap-tour.min.css"} \ No newline at end of file
diff --git a/themes/default/template/no_photo_yet.tpl b/themes/default/template/no_photo_yet.tpl
index 25673e1ac..c386e0dd1 100644
--- a/themes/default/template/no_photo_yet.tpl
+++ b/themes/default/template/no_photo_yet.tpl
@@ -31,7 +31,7 @@ border:2px solid #dddddd;
#noPhotoWelcome {font-size:25px; color:#555;text-align:center; letter-spacing:1px; margin-top:30px;}
.bigButton {}
-.bigButton {text-align:center; margin-top:120px;}
+.bigButton {text-align:center; margin-top:100px;}
.bigButton a {
background-color:#666;
diff --git a/upgrade.php b/upgrade.php
index 7c707bd7c..89aa07ede 100644
--- a/upgrade.php
+++ b/upgrade.php
@@ -438,14 +438,13 @@ if ((isset($_POST['submit']) or isset($_GET['now']))
$page['infos_sav'] = $page['infos'];
$page['infos'] = array();
- // c13y_upgrade plugin means "check integrity after upgrade", so it
- // becomes useful just after an upgrade
+ /* might be usefull when we will have a real integrity checker
$query = '
REPLACE INTO '.PLUGINS_TABLE.'
(id, state)
VALUES (\'c13y_upgrade\', \'active\')
;';
- pwg_query($query);
+ pwg_query($query);*/
// Delete cache data
invalidate_user_cache(true);