Bei "hover" Unterkategorie Foto einblenden

N´abend zusammen,

ich möchte gerne aus einer Unterkategorieübersicht bei hover auf die kleinen Unterkategorieboxen das Foto welches beim Ziel hinterlegt ist, bereits einblenden, also in meiner Test-DB meine ich das wie folgt:
http://www.px-performance.de/demoshop/PX-Motor/

Wenn ich nun auf “Kurbelwelle” zeige, dann möchte ich das Explosionsfoto, welches beim Ziel http://www.px-performance.de/demoshop/PX-Motor/Kurbelwelle/ oben angezeigt wird bereits eingeblendet bekommen.

Hintergrund: der Kunde soll so schon sehen, welche Ersatzteile ihn dort erwarten.

Dasselbe würde ich gerne im linken Kategoriebaum realisieren, der mir angezeigt wird, wenn ich z.B. im Artikel “Kurbelwelle PIAGGIO Vespa PX125-150” bin.

Nun übersteigt das echt meine Kenntnisse, ich bin da noch nicht so fit, was die Programmierung angeht.
Wie würdet ihr das machen, wenn es denn geht. Über Java ?
Oder alles per CSS. Über eine kleine Hilfestellung freue mich mich sehr.

Besten Dank und viele Grüße
Thomas

Hallo zusammen,

ich denke, ich würde das gerne mit jquery umsetzen, weil man da noch viele Möglichkeiten hat.
Nun betrete ich da echt Neuland, aber ich versuche mich mal da rein zu arbeiten, Tut´s gibt es ja viele im Internet, da muss ich mal das passende für mich rausfinden.

Das knackige daran wird wohl sein, den Wert abzufragen, welches Foto denn nun aufgerufen und eingeblendet werden soll und wie ich das Script dann im Template integriere.

Ich möchte ja hier auch keine fertige Lösung präsentiert bekommen, sondern schon selber verstehen, wie Oxid in den feinen Details auch funktioniert.

Aber über eine kleine Hilfestellung freue ich mich trotzdem sehr…

Beste Grüße
Thomas

ist nur jQuery Neuland für dich oder auch css, html und php?

html und css Kenntnisse habe ich, php ist auch Neuland für mich…

Schau dir mal Smarty an, das wirst du brauchen um die Shop Templates zu verstehen.

und bei jQuery wäre es am einfachsten ein fertiges Plugin zu benutzen.
In dem Fall würde ich irgendein tooltip plugin nehmen, vllt das hier http://calebjacob.com/tooltipster/ sieht jedefall noch relativ einfach aus.

dann siehst du aus der jQuery Plugin Doku, welche Daen das Plugin braucht und wie es aussehen muss, dann schaust du ins Template was du hast und versuchst beide auf einen gemeinsamen Nenner zu bringen. (was meistens die Erweiterung/Anpassung des Templates bedeutet)

Danke…hab mir mal die smarty Doku in Deutsch gezogen und werde mal lesen, verstehen, testen…und dann jquery…
Schönen Abend noch…

Viele Grüße
Thomas

Hi Vanilla Thunder,

ich hab Dir eine PN geschrieben…

Gruß
Thomas

also, hier folgt eine kleine Anleitung mit allen Überlegungen, die zum Ziel geführt haben:

1) Script beschaffen:
Ich benutze oft “jQuery Tools Tooltip” http://jquerytools.org/demos/tooltip/index.html
Und es ist relativ einfach in der Benutzung.

Auf der Download Seite drücken wir alles weg und wählen nur “Tooltip” und “Dynamic plugin” aus.
Auf [Download now] drücken und dann zurück auf die Seite mit der Beschreibung.

2) Template anpassen:
Der Beschreibung entnehmen wir, dass der Inhalt vom Tag-Attribut “title” angezeigt wird, also müssen wir das Bild in title="" reinbekommen.
Öffnen wir jetzt das Template: azure/tpl/page/list/list.tpl

Ein Blick in den Quelltext der geladenen Kategorieseite verrät, dass wir nach den Code

<div class="subcatPicOnly"><img src="....." /></div>

suchen müssen, also suchen wir im Template nach einem ähnlichen Konstrukt. Und tatsächlich findet man es in der Zeile 100:


<div class="subcatPicOnly">
[{if $iconUrl}]
<a href="[{ $category->getLink() }]">
<img src="[{$category->getIconUrl() }]" alt="[{ $category->oxcategories__oxtitle->value }]">
</a>
[{/if}]
</div>

Das bedeutet so viel, dass die Unterkategorie $category heißt. Jetzt brauchen wir die URL des großen Hauptbildes. Das Hauptbild wird ganz oben auf der Kategorieseite angezeigt, also schaue mir mal nach oben. Da finden wir auch ein einziges Bild, dessen URL mit “getThumbUrl()” abgerufen wird.

Voller Hoffnung erweitern wir unseren Code also um title="" und getThumbUrl():

<img src="[{$category->getIconUrl() }]" title="[{ $category->getThumbUrl()}]" alt="[{ $category->oxcategories__oxtitle->value }]">

abspeichern, tmp/ leeren und die Seite neuladen.

Trommelwirbel Den Quelltext anschauen, und…

<img src="http://..........icon.jpg" title alt="Fashion" />

…schei…benhonig… “title” ist da, aber da ist nix drin. Theoretisch folgen jetzt 2-3 schlaflose Nächte auf der Suche nach der Ursache und dann noch eine Nacht, in der man im Forum alle Threads der letzten 3 Jahre durchsucht. Da ich das aber schon hinter mir habe, hier die Lösung:
Wir öffnen die Datei application/models/oxcategory.php und suchen nach


public function __construct()
{
	parent::__construct();
	$this->init( 'oxcategories' );
}

und machen daraus:


public function __construct()
{
	$this->_blUseLazyLoading = true;
	self::$_blDisableFieldCaching[get_class( $this )] = true;
	parent::__construct();
	$this->init( 'oxcategories' );
}

(Nach einem Shop Update musst du das wahrscheinlich erneuern, oder man könnte das auch als Modul verpacken)
Speichern, tmp/ leeren, neuladen, läuft.
Allerdings steht im title="" jetzt die Bild-URL aber noch kein richtiges Bild, also bauen wir ein drumrum:

<img src="[{$category->getIconUrl() }]" title="<img src='[{ $category->getThumbUrl()}]' width='550' />" alt="[{ $category->oxcategories__oxtitle->value }]">

Ein Paar Zeilen höher gibts ein ähnliches KOnstrukt, allerdings ist da die <div class=“subcatPic” statt “subcatPicOnly”, da fügen wir mal das selbe ein.

3) Script einbauen:
Erst mal laden wir die im Punkt 1 heruntergeladene Datei auf dem Server hoch: in out/azure/src/js/ rein.
in der list.tpl haben wir ganz oben ein paar [{oxscript add="" }] und [{oxscript include="" }] gesehen. Es läuft also darauf hinaus, dass auf diese Weise die Scripts eingebunden werden.

Fügen wir also auch unser Script so ein (direkt nach den anderen [{oxscript}]:

[{oxscript include="js/jquery.tools.min.js"}]

Wenn man vorhin aufgepasst hat, stand auf der Download Seite irgendwas mit jQuery 1.7.2
Schauen wir mal, welches wir im Shop haben. Im Browser den Quelltext angucken, auf jquery.min.js klicken und da steht…1.5.1
Man könnte jetzt versuchen, aber wird nicht klappen, daher bauen wir neueres jQuery ein:
in azure/tpl/layout/base.tpl gibts weiter unten

[{oxscript include="js/libs/jquery.min.js" priority=1}]

wir machen daraus:

[{oxscript include="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" priority=1}]

In der Beschreibung standen auch ein paar Zeilen CSS, die wir einbauen sollten. In weiser Voraussicht habe ich die Zeilen etwas angepasst, fügen wir den Code direkt nach dem [{oxscript}] ein

<style>
.tooltip {
    display:none;
    width: 550px;
	z-index: 999;
	border: 2px solid #0090cf;
  }
</style>

Jetzt fehlt nur noch der Aufruf des Scripts selbst, in der Beschreibung stand es so:

$("#demo img[title]").tooltip();

Auf unsere Umstände angepasst wäre es so:

[$('img[title]').tooltip();

Vorhin beim Runterladen haben wir auch “Dynamic plugin” mit ausgewählt, der sorgt dafür, dass der Tooltip innerhalb des Bildschirms bleibt, wenn das Bild theoretisch über die Grenzen hinausgehen würde, also hängen wir noch den Code für den dynamic plugin dran. Sieht im Endeffekt so aus:

[{oxscript add="$('img[title]').tooltip().dynamic({ bottom: { direction: 'top', bounce: true } });"}]

“direction: top” beschreibt die Position des Tooltips, in der jQuery Tools Dokumentation steht mehr darüber, falls Aufklärungsbedarf besteht.

Und das wars eigentlich schon: speichern, tmp/ leeren, neuladen.

sehr hübsch!

Aber ist noch nicht eingebaut, oder?

I’m neusten azure? Nein, da musste man ja erst eine core Datei anpassen.

N´abend,

wow…das ist unglaublich hilfsbereit von Dir vanilla thunder, ich bin echt beeindruckt und Dir sehr dankbar. Momentan liege ich noch mit Fieber im Bett, aber sobald ich mich wieder besser fühle, werde ich das mal in mein Child-Theme meines Demo-Shops zum Testen einsetzen und berichten.
Vielen Dank nochmals für die ausführliche Vorarbeit. Ich muss gestehen…ich beneide DIch um Dein Wissen zur Shop-Programmierung.

Beste Grüße
Thomas

Moinsen vanilla,

ein ganz großes merci nochmal…ich habe es nach Deiner Anleitung eingebaut und…läuft.
Ganz großes Kino für mich, daaaaaanke.
http://www.px-performance.de/demoshop/PX-Motor/

Ich justiere den Rahmen noch bissel mit css, aber das sollte ich hinbekommen.

Beste Grüße
Thomas

Hallo vanilla,

ich hab da noch mal eine kleine Frage:
Wenn ich die Seite aufrufe, dann blendet sich der Tooltip beim ersten mal so mittig ein, quasi in den Button direkt rein, wo sich der Cursor befindet. Ab dem Zweiten Hover ist es dann richtig, also Ausrichtung oberhalb, links, mittig, oder rechts.
Kann man beim Link einen Thread vorher testen, das tritt bei mir beim neuesten Chrome, und Firefox gleichermaßen auf. Nur der neue Explorer 9 macht es gleich richtig.

Kann ich da was machen ?

Besten Dank und viele Grüße
Thomas

Hi,
das passiert, weil der Browser beim ersten Anzeigen des Tooltips die Größe des Bildes nicht kennt und somit nicht berechnen kann, wo der Tooltip angezeigt werden soll.

Man könnte zwar die dynamische Positionierung des tooltips abschalten, aber dann können die Tooltips auch außerhalb des sichtbaren Bereiches angezeigt werden.

ok.verstehe.
Ich habe mir mal den js-code angesehen und nach stundenlangem probieren habe ich es hinbekommen, dass die Ausrichtung oben immer zentriert ist, den Code habe ich hier angepasst:

if (f.isShown())
					return f;
				h.stop(!0, !0);
				var o = c(d, h, e);
				e.tip && h.html(d.data("title")), b = a.Event(), b.type = "onBeforeShow", g.trigger(b, [o]);
				if (b.isDefaultPrevented())
					return f;
				var z = a(window), y = z.width();
				y=y-(y/2)-350;
				o = c(d, h, e), h.css({
					position : "absolute",
					top : o.top,
					left : y
				}), n = !0, m[0].call(f, function() {
					b.type = "onShow", n = "full", g.trigger(b)
				});

Ich habe also left mit einer variablen deklariert, die vorab die Bildschirmmaße liest.
Kann ich denn nicht vielleicht irgendwo im Code die Bildgröße hart einstellen, oder hilft mir das auch nicht weiter?
Die Bildgröße der Vorschau ist nämlich festgelegt.

So ist es halt ungünstig, weil der Kunde beim ersten Aufruf mit dem Tooltip den Cursor verdeckt und nicht links oder rechts den Tooltip der nebenstehenden Kategorie einblenden kann.

Hier nochmal der vollständige js-Code:

/*!
 * jQuery Tools v1.2.7 - The missing UI library for the Web
 *
 * tooltip/tooltip.js
 * tooltip/tooltip.dynamic.js
 *
 * NO COPYRIGHTS OR LICENSES. DO WHAT YOU LIKE.
 *  &&(f-=i)
 * http://flowplayer.org/tools/
 *
 */
(function(a) {
	a.tools = a.tools || {
		version : "v1.2.7"
	}, a.tools.tooltip = {
		conf : {
			effect : "toggle",
			fadeOutSpeed : "fast",
			predelay : 30,
			delay : 30,
			opacity : 1,
			tip : 0,
			fadeIE : !1,
			position : ["top", "center"],
			offset : [-20, 0],
			relative : !1,
			cancelDefault : !0,
			events : {
				def : "mouseenter,mouseleave",
				input : "focus,blur",
				widget : "focus mouseenter,blur mouseleave",
				tooltip : "mouseenter,mouseleave"
			},
			layout : "<div/>",
			tipClass : "tooltip"
		},
		addEffect : function(a, c, d) {
			b[a] = [c, d]
		}
	};
	var b = {
		toggle : [
		function(a) {
			var b = this.getConf(), c = this.getTip(), d = b.opacity;
			d < 1 && c.css({
				opacity : d
			}), c.show(), a.call()
		},
		function(a) {
			this.getTip().hide(), a.call()
		}],
		fade : [
		function(b) {
			var c = this.getConf();
			!a.browser.msie || c.fadeIE ? this.getTip().fadeTo(c.fadeInSpeed, c.opacity, b) : (this.getTip().show(), b())
		},
		function(b) {
			var c = this.getConf();
			!a.browser.msie || c.fadeIE ? this.getTip().fadeOut(c.fadeOutSpeed, b) : (this.getTip().hide(), b())
		}]

	};
	function c(b, c, d) {
		var e = d.relative ? b.position().top : b.offset().top, f = d.relative ? b.position().left : b.offset().left, g = d.position[0];
		e -= c.outerHeight() - d.offset[0], f += b.outerWidth() + d.offset[1], /iPad/i.test(navigator.userAgent) && (e -= a(window).scrollTop());
		var h = c.outerHeight() + b.outerHeight();
		g == "center" && (e += h / 2), g == "bottom" && (e += h), g = d.position[1];
		var i = c.outerWidth() + b.outerWidth();
		g == "center" && (f -= i / 2), g == "left" && (f -= i);
		return {
			top : e,
			left : f
		}
	}

	function d(d, e) {
		var f = this, g = d.add(f), h, i = 0, j = 0, k = d.attr("title"), l = d.attr("data-tooltip"), m = b[e.effect], n, o = d.is(":input"), p = o && d.is(":checkbox, :radio, select, :button, :submit"), q = d.attr("type"), r = e.events[q] || e.events[ o ? p ? "widget" : "input" : "def"];
		if (!m)
			throw "Nonexistent effect \"" + e.effect + "\"";
		r = r.split(/,\s*/);
		if (r.length != 2)
			throw "Tooltip: bad events configuration for " + q;
		d.on(r[0], function(a) {
			clearTimeout(i), e.predelay ? j = setTimeout(function() {
				f.show(a)
			}, e.predelay) : f.show(a)
		}).on(r[1], function(a) {
			clearTimeout(j), e.delay ? i = setTimeout(function() {
				f.hide(a)
			}, e.delay) : f.hide(a)
		}), k && e.cancelDefault && (d.removeAttr("title"), d.data("title", k)), a.extend(f, {
			show : function(b) {
				if (!h) {
					l ? h = a(l) : e.tip ? h = a(e.tip).eq(0) : k ? h = a(e.layout).addClass(e.tipClass).appendTo(document.body).hide().append(k) : ( h = d.next(), h.length || ( h = d.parent().next()));
					if (!h.length)
						throw "Cannot find tooltip for " + d
				}
				if (f.isShown())
					return f;
				h.stop(!0, !0);
				var o = c(d, h, e);
				e.tip && h.html(d.data("title")), b = a.Event(), b.type = "onBeforeShow", g.trigger(b, [o]);
				if (b.isDefaultPrevented())
					return f;
				var z = a(window), y = z.width();
				y=y-(y/2)-350;
				o = c(d, h, e), h.css({
					position : "absolute",
					top : o.top,
					left : y
				}), n = !0, m[0].call(f, function() {
					b.type = "onShow", n = "full", g.trigger(b)
				});
				var p = e.events.tooltip.split(/,\s*/);
				h.data("__set") || (h.off(p[0]).on(p[0], function() {
					clearTimeout(i), clearTimeout(j)
				}), p[1] && !d.is("input:not(:checkbox, :radio), textarea") && h.off(p[1]).on(p[1], function(a) {
					a.relatedTarget != d[0] && d.trigger(r[1].split(" ")[0])
				}), e.tip || h.data("__set", !0));
				return f
			},
			hide : function(c) {
				if (!h || !f.isShown())
					return f;
				c = a.Event(), c.type = "onBeforeHide", g.trigger(c);
				if (!c.isDefaultPrevented()) {
					n = !1, b[e.effect][1].call(f, function() {
						c.type = "onHide", g.trigger(c)
					});
					return f
				}
			},
			isShown : function(a) {
				return a ? n == "full" : n
			},
			getConf : function() {
				return e
			},
			getTip : function() {
				return h
			},
			getTrigger : function() {
				return d
			}
		}), a.each("onHide,onBeforeShow,onShow,onBeforeHide".split(","), function(b, c) {
			a.isFunction(e[c]) && a(f).on(c, e[c]), f[c] = function(b) {
				b && a(f).on(c, b);
				return f
			}
		})
	}
	a.fn.tooltip = function(b) {
		var c = this.data("tooltip");
		if (c)
			return c;
		b = a.extend(!0, {}, a.tools.tooltip.conf, b), typeof b.position == "string" && (b.position = b.position.split(/,?\s/)), this.each(function() {
			c = new d(a(this), b), a(this).data("tooltip", c)
		});
		return b.api ? c : this
	}
})(jQuery);
(function(a) {
	var b = a.tools.tooltip;
	b.dynamic = {
		conf : {
			classNames : "top right bottom left"
		}
	};
	function c(b) {
		var c = a(window), d = c.width() + c.scrollLeft(), e = c.height() + c.scrollTop();
		return [b.offset().top <= c.scrollTop(), d <= b.offset().left + b.width(), e <= b.offset().top + b.height(), c.scrollLeft() >= b.offset().left]
	}

	function d(a) {
		var b = a.length;
		while (b--)
		if (a[b])
			return !1;
		return !0
	}
	a.fn.dynamic = function(e) {
		typeof e == "number" && ( e = {
			speed : e
		}), e = a.extend({}, b.dynamic.conf, e);
		var f = a.extend(!0, {}, e), g = e.classNames.split(/\s/), h;
		this.each(function() {
			var b = a(this).tooltip().onBeforeShow(function(b, e) {
				var i = this.getTip(), j = this.getConf();
				h || ( h = [j.position[0], j.position[1], j.offset[0], j.offset[1], a.extend({}, j)]), a.extend(j, h[4]), j.position = [h[0], h[1]], j.offset = [h[2], h[3]], i.css({
					visibility : "hidden",
					position : "absolute",
					top : e.top,
					left : e.left
				}).show();
				var k = a.extend(!0, {}, f), l = c(i);
				if (!d(l)) {
					l[2] && (a.extend(j, k.top), j.position[0] = "top", i.addClass(g[0])), l[3] && (a.extend(j, k.right), j.position[1] = "right", i.addClass(g[0])), l[0] && (a.extend(j, k.bottom), j.position[0] = "bottom", i.addClass(g[2])), l[1] && (a.extend(j, k.left), j.position[1] = "left", i.addClass(g[3]));
					if (l[0] || l[2])
						j.offset[0] *= -1;
					if (l[1] || l[3])
						j.offset[1] *= -1
				}
				i.css({
					visibility : "visible"
				}).hide()
			});
			b.onBeforeShow(function() {
				var a = this.getConf(), b = this.getTip();
				setTimeout(function() {
					a.position = [h[0], h[1]], a.offset = [h[2], h[3]]
				}, 0)
			}), b.onHide(function() {
				var a = this.getTip();
				a.removeClass(e.classNames)
			}), ret = b
		});
		return e.api ? ret : this
	}
})(jQuery);

Beste Grüße
Thomas