Alles rund um das ausgewählte Thema ... Zeige max. 5 Stories pro Seite von 5
Web-Entwicklung mit Notes / Domino
Domino, Web
Nachdem ich ja zuletzt gezeigt habe, wie ich meine Bilder in meine Datenbank bekomme, wollte ich hier mal zeigen, wie ich die webseiten erstelle. Das ganze stellt hier nur einen groben Abriss dar. Auf einzelne Bereiche, wie z.B. das teilen eines Eintrages auf FB zeige ich mal seperat.
Das ganze beginnt wie fast alles in Notes mit einem Form in welchem die Bilder ausgewaehlt werden und der eigentliche Text verfasst wird.
Es gibt ein Hauptbild(mit welchem das Carousel startet) und bis zu 8 Subbilder. Das Carousel kommt mit Bootstrap mit. Der HTML-Code ist etwas komplexer, daher wird es schon in dem Dokument berechnet und nicht erst in den Ansichten.
In den jeweiligen Ansichten wird dann der dynamische Teil des HTML zusammengebaut. Wie man sieht, berechnen die ganzen Spaltenformeln immer reines HTML.
Das zusammenfuehren erfolgt dann in den jeweilgen webForms ($$ViewTemplate...).
Auch hier ist alles plain HTML. Das schoene ist, das man aber mit Notes mitteln (Formeln oder Script) diverse Dinge immer dynamisch berechnen kann, wie Z.B. die Navigation als ComputedText.
Das ganze kommt immer entsprechend in Subforms und kann entsprechend in allen ViewTemplates verwendet werden.
Die fuer Bootstrap benoetigten Resourcen habe ich in den ueber den PackageExplorer importiert und nicht bei den Resourcen. Hier sind auch mein CSS, Javascript (Lazyload) und Icons eingebunden.
Die 3 Bereiche sind alle von dieser Struktur her gleich aufgebaut. Ausnahme bilden die Fixed-Content Seiten (About und Impressum). Mit der Einfuehrung von Xpages hatte ich das zu beginn einmal damit gemacht, aber Vorteile hat man davon nicht. Bei reinen Web-Anwendungen erhoeht es nur unnoetig die komplexitaet.
Das ganze ist fuer den Content (mit den ganzen Bildern) sogar einigermassen perfomant (Google Web-Analytic).
Erstellen der sitemap und des rss-feeds mit Domino
Domino, RSS, Sitemap
Warum ueberhaupt eine Sitemap erstellen? Nun gut, man koennte es Google und konsorten einfach selbst ueberlassen die Seite richtig zu indexieren, oder aber dabei behilflich sein ueber eine Sitemap (Vor allem wenn man Content in tieferen ebenen hat, der sich sonst nicht so leicht finden laesst.).
Die Sitemap.XML ist vom Notes-Design her auch nichts anderes als eine Ansicht.
Damit das ganze auch einfach als sitemal.xml aufgerufen werden kann, wird die Ansicht mit dem alias sitemap.xml gespeichert. Dann muss nur noch ein entsprechendes $$ViewTemplate erstellt werden.
Das ganze sieht dann im Browser so aus.
Das ganze habe ich dann entsprechend bei Google, Bing etc. entsprechend ueber deren Consolen hinterlegt und diese habe diese als Valide erkannt und scannen die Seiten nun entsprechend.
Mit dem rss Feed verhaellt es sich im Prinzip aehnlich. Auch hier wird erst einmal eine entsprechende Ansicht erstellt. Der Content ist aufgrund des Formates etwas komplexer (auch wegen der Bilder).
Auch hier wird dann entsprechend ein $$ViewTemplate erstellt.
Auch das laesst sich im Browser entsprechend aufrufen.
Aber interessanter ist natuerlich das einbinden des rss-Feeds in eine entsprechende App. Hier mal als Beispiel auf dem iPad Bloglovin.
Oder auf dem iPhone mit Newsify oder Feedly.
Automatisiertes erstellen von Pins auf Pinterest via RSS
Domino, Pinterest, RSS, Social
Ich hatte ja bereits die Moeglichkeit geschaffen Bilder von meiner Seite via Agent auf Pinterest zu teilen. Fuer mich als Seitenbetreiber ist das aber zu umstaendlich, bzw. moechte ich ja auch bestimmen was genau und in welchem Board das ggf. auftauchen soll. Auch moechte ich ggf. wissen welche Bilder von meiner Seite aus gepint wurden.
Pinterest bietet hier zwei Moeglichkeiten Pins automatisiert zu erstellen. Das eine ist eine CSV-Datei (welche aber wohl nur fuer Video-Pins verwendet werden kann) oder aber via RSS-Feed. Da ich aber eh schon einen RSS-Feed fuer die Seite habe und hiermit schon etwas Erfahrung habe, waehle ich diesen Weg. Dieser ist auch weit aus angenehmer, da er viel besser automatisiert werden kann.
Fuer die Zuordnung zu einem Board habe ich hierzu ein Form erstellt, welches den Boardnamen erfasst und noch ein paar technische Felder.
Das Form enthaellt zugleich die benoetigten RSS-Formatierungen. Es wird ueber eine entsprechende URL aufgerufen. Der WebQueryOpen-Agent generiert das eigentliche XML beim oeffnen und schreibt es in das RichText-Feld.
board = StrRight(doc.getItemValue("Query_String_Decoded")(0), "=")
Set locView = db.Getview("HV8020")
Set pinDC = pinView.Getalldocumentsbykey(board, true)
Set pinDoc = pinDC.Getfirstdocument()
rssString = ""
Do While Not pinDoc Is Nothing
Set locDoc = locView.Getdocumentbykey(pinDoc.Getitemvalue("loc_unique")(0), true)
If Not(locDoc Is Nothing) Then
pTitle = "" & locDoc.Getitemvalue("searched_type")(0) & ": " & locDoc.Getitemvalue("gs_name")(0) & "" & Chr(13)
pLink = "https://www.workm.de/WV5500?OpenView&RestrictToImage=" & pinDoc.Getitemvalue("uniqueID")(0) & "" & Chr(13)
pDesc = "" & locDoc.Getitemvalue("Description")(0) & "" & Chr(13)
tX = StrRightBack(pinDoc.Getitemvalue("Subject")(0),"\")
pEncl = || & Chr(13)
pPubD = "" & pinDoc.Getitemvalue("pinPublished")(0) & "" & Chr(13)
pGUID = || & pinDoc.Getitemvalue("uniqueID")(0) & || & Chr(13)
pCat = "" & pinDoc.Getitemvalue("laTop")(0) & "" & Chr(13)
pItem = "" & pTitle & pLink & pDesc & pEncl & pPubD & pGUID & pCat & "" & Chr(13)
End If
rssString = rssString + pItem
Set pinDoc = pinDC.Getnextdocument(pinDoc)
Loop
If (rssString = "") Then
rssString = ""
End If
' Call doc.Replaceitemvalue("socialArg", arg)
Set smItem = New NotesRichTextItem(doc, "RSS")
Call smItem.Appendtext(rssString)
Wenn man dann das entsprechende Dokument im Browser aufruft sieht das ganze so aus. Das ganze habe ich natuerlich ueber einen Validator mal abgeprueft.
Nun kann ich bei Pinterest in meinem Account den RSS-Feed entsprechend konfigurieren.
Die Zuweisung der Bilder erfolgt nun im Notes indem ich eine Verknuepfung der Bilder zu dem jeweiligen Board-Dokument erstelle. Dadurch wird der RSS-Feed automatisch aktuallisiert und Pinterest zeigt das Bild nach spaetestens 24h an. Wenn ein Board neu erstellt wird, sogar gleich.
Um jetzt mitzubekommen ob jemand ein Bild von meiner Seite aus Pinned muss ich die Pin-ID im HTML hinterlegen. Die Pin-ID muss ich hierzu aber erst ermitteln. Hierzu nutze ich wieder eine Rest-API welche Pinterest zur Verfuegung stellt.
Es wird der Benutzer und das Board uebergeben. Ueber den link, welcher den unique-Identifier von mir enthaellt, kann ich die Zuordnung machen und die Pin-ID in mein Image-Dokument zurueckschreiben. Hierdurch wird dann auch das HTML auf meiner Seite entsprechend angepasst.
Pinterest prueft die Seite entsprechend nun oefters. Was Pinterest allerdings nicht macht, es aktuallisiert nicht die Informationen! Wenn ich im Nachhinein eine Bewertung der Lokation durchfuehre, die Bilder aber bereits veroeffentlich habe, dann wird diese Beschreibung hier nur bei neuen Pins uebernommen.
Erstellen von Social-Media sharing actions
Domino, Social-Media, Shareing
Zum Thema Social-Media bin ich ja etwas zwiespaeltig eingestellt. Ich hab ja nichts gegen das Teilen von Content auf diesen Plattformen, allerdings habe ich etwas gegen das tracking dieser Plattformen. Diese Plattformen nieten zur einfachen Einbindung in die eigene Website schoen vorgefertigte Plug-ins an, welche aber etwas mehr Funktionalitaet haben als nur das Teilen des Contents. Deshalb habe ich das Teilen etwas anders geloest, ohne hierfuer auf die zur Verfuegung gestellten Plug-ins oder Code-Bloecke zurueckzugreifen.
Ich habe mal 4 Optionen zur Verfuegung gestellt (Facebook, Twiter, Pinterest und Mail).
Die Platformen bieten alle (noch) eine Option zum Teilen via URL-Link an, ueber welchen die Plattform aufgerufen werden kann und ueber Parameter dann die entsprechende Info uebergeben werden kann. Der Umfang der Parameter ist aber unterschiedlich und wie bei Facebook inzwischen auf einen Parameter (den direkten Link) sehr eingeschraenkt.
Als Beispiel hier einmal der Link fuer Pinterest (mit entsprechenden Variablen) ...
Man hat ueber diesen Weg allerdings keine direkte auswertbarkeit ob jemand die Aktion ausgefuehrt hat. Daher habe ich das ganze auf einen Agenten ausgelagert, welchem die Plattform als auch der Schluessel zum entsprechenden Bild mitgegeben wird.
Der Agent ermittelt die entsprechenden Werte fuer den auszufuehrenden Link und erstellt auch noch ein Dokument fuer mich als Counter.
Call doc.Replaceitemvalue("Form", "F7000")
Call doc.Save(true, false, true)
arg = atfRight(session.Documentcontext.Query_String(0), "&")
Call doc.Replaceitemvalue("socialArg", arg)
sid = atfRight(arg, "=")
Call doc.Replaceitemvalue("socialSid", sid)
typ = atfLeft(arg, "=")
Call doc.Replaceitemvalue("socialTyp", typ)
Call doc.Save(True, False, True)
Print "Content-Type: text/html"
Print "Status: 302 Moved Temporarily"
Select Case typ
Case "FBS"
' FaceBook Single Story > Image Gallery
Print "Location: https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fwww.workm.de%2FWV5500%3FOpenView%26RestrictToImage%3D" & sid
Case "FBM"
' FaceBook Multi Article > Artikel
Print "Location: https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fwww.workm.de%2FWV1500%3FOpenView%26RestrictToArticle%3D" & sid
Case "TWFS"
' Twitter Single
Print "Location: https://twitter.com/intent/tweet?url=www.workm.de%2FWV5500%3FOpenView%26RestrictToImage%3D" & sid
Case "PRS"
' Pinterest Single
Set sDoc = sView.Getdocumentbykey(sid, true)
If Not(sDoc Is Nothing) Then
Print "Location: https://pinterest.com/pin/create/button/?url=https%3A%2F%2Fwww.workm.de%2FWV5500%3FOpenView%26RestrictToImage%3D" & sid & "&media=https%3A%2F%2Fwww.workm.de%2F" & sDoc.getItemValue("uKey")(0) & "%2F$File%2F" & sDoc.getItemValue("PreviewFilename")(0) & "%3FOpenElement&description=" & sDoc.getItemValue("GV_labelAnnotations")(0)
Else
' ...
End If
End Select
Der “Counter” ist allerdings in der Hinsicht limitiert, als dass er nur das aufrufen der Aktion dokumentiert. Wenn der Anwender die Aktion abbricht bekomme ich das nicht mehr mit.
Beim oeffnen des Links wird noch nicht das ausgewaehlte Bild angezeigt! Diese erfolgt erst nach dem publizieren!
Damit das allerdings auch funktioniert, muss die Seite, welche dem Link mitgegeben wird entsprechende Tags enthalten. Das sind die OpenGraph tags.
Das erfolgt entsprechend Notes via @Formula im entsprechenden $$ViewTemplate.
Das ganze funktioniert fuer Facebook, Twitter und Pinterest in etwa gleich. Nur das sharing via Mail wird ueber einen mailTo link generiert.
Eigentlich dachte ich ja, ich koennte ueber das log-Dokument spaeter validieren ob der Anwender das Bild tatsaechlich geteilt hat. Bei FB gebe ich hierzu eine App-ID mit an, allerdings gibt das die API von denen nicht her, man kann deren Plug-in Loesung nicht komplett nachbilden. Aber dafuer muss ich bei meiner Loesung nicht mit meinen (euren) Daten bezahlen :).
Einbinden von Bildern in Notes/Domino
Domino, Images
Die Seite hier besteht ja hauptsaechlich aus bildern. Hier einmal kurz dokumentiert, wie ich die Bilder importiere und verarbeite.
Aufgrund der Menge an Bilder (ca. 5000) habe ich mich nach einer einfachen und kostenguenstigen Loesung umgeschaut, man muss ja nicht alles selbst erfinden. Hier bin ich Voith's Seite gestosen. Er hat ein Tool hierfuer geschrieben was zum groessten Teil genau das abbildet was man auch von Wordpress-Seiten her kennt. Man kann die Bilder in mehreren Formaten und groessen importieren. Weiterhin kann ich mir auch die Bilder direkt in einer Notes-Ansicht anzeigen lassen (was aber auch so gehen wuerde).
Bilder koennen in einer Ansicht dargestellt werden, wenn sie auch als ImageResource hinterlegt sind, was man ueber das Tool automatisieren kann.
Auch koennen die Bildinformationen mit ausgelesen werden.
Weiterhin schneide ich die Bilder auch hiermit zu und haenge diese in ein Notesdokument. Hierueber erfolgt auch dann die Darstellung spaeter im Web.
Nachdem die Bilder impotiert sind, erstelle ich noch eine base64-Version davon und tage die Bilder via Google-Vision (das ist dann die Kategorisierung der Bilder von A-Z). Die Webprogrammierung zeige ich spaeter einmal.
Das ganze kommt als dll und man kann sich hierfuer dann eine ScriptLibrary erstellen.
Ueber einen Script-Agenten rufe ich das ganze auf.
Dim impOpt As String
Dim nID As String
Dim RC As Long
Dim c As Integer
Set db = s.CurrentDatabase
filenames = ws.OpenFileDialog( True, "Image to be imported","All files|*.*|Jpegs|*.jpg","c:\temp")
c = 1
If Not(IsEmpty(filenames)) Then
ForAll filename In filenames
Print "processing file " & c
strFileName = filename
Set doc = db.CreateDocument
Call doc.ReplaceItemValue("Form", "F5000")
Call doc.Replaceitemvalue("Subject", strFileName)
Call doc.Computewithform(False, False)
Call doc.Save(True, False, True)
nID = doc.Noteid
impOpt = ""
impOpt = impOpt & "SetLogLevel:5"
impOpt = impOpt & "; " & "ProcessTimeField:pTime"
impOpt = impOpt & "; " & "ExtractEXIFToField:exif,both"
impOpt = impOpt & "; " & "ExtractIPTCToField:iptc,both"
impOpt = impOpt & "; " & "AutoOrientation:1"
impOpt = impOpt & "; " & "AttachPreviewFile:" & nID & "spreview,prv,640,480,5"
impOpt = impOpt & "; " & "AttachOrginalFile:orgImage"
impOpt = impOpt & "; " & "AttachImportFile:orgImage"
If strFileName <> "" Then
If (ImportImageAsResource(db.Server, db.FilePath, doc.UniversalID, "thumb", 160, 120, "imageR", strFileName, impOpt) <> 0) Then
'issue
MsgBox "Issue at importing "& strFileName, 64, "info"
GoTo nextFile
Else
'ok
' speichern?
End If
End If
nextFile:
c = c + 1
End ForAll
Else
MsgBox "No files selected.", 64, "info"
Exit sub
End If
Das ganze hat einen ‚kleinen‘ Nachteil, welcher nicht von Tool selbst her kommt, sondern von Notes. Man kann nicht beliebig viele ImageResourcen erstellen. Ueber 5000 faengt, je nach Version von Notes, das ganze etwas instabil zu werden. Aber fuer eine solche Seite ist das ja schon ganz schoen viel ;)
Bei meiner Wordpress-Seite werden die Bilder in einem Azure-Blop gespeichert, was natuerlich fuer wesentlich mehr Bilder reichen wuerde und ich kann dann auch gleich mit Azure-Vision Taggen, aber das ist wieder eine andere Geschichte.
Zwei Dinge noch zu der Lib. Zum einen ist das ganze mit 10$-75$ sehr guenstig und zum zweiten ist der Support sehr gut! Wenn man Fragen hat, dann bekommt man immer prombt eine Antwort! Ach ja und das ganze ist sehr gut Dokumentiert!!