2017-09-26 3 views
7

Je dois créer un objet fenêtre pour que le fichier externe, chargé dans iframe, puisse appeler la fonction nativescript.Objet window dans nativescript

J'ai spécifiquement besoin d'un objet fenêtre car le fichier que je charge peut être n'importe quel fichier conforme à SCORM lié à LMS.

Merci

Modifier: Le fichier que je l'ai chargé est un fichier SCORM. Ils recherchent window.API object/window.parent.API et ainsi de suite, pour démarrer la communication avec le conteneur dans lequel ils ont été chargés. Je ne peux pas modifier ce fichier.

Dites-moi si plus de détails sont nécessaires.

+0

Veuillez indiquer pourquoi downview? – Deepika

+0

'window' dans les navigateurs est comment l'objet javascript global est nommé, il expose certains objets et fonctions qui ne sont valables que dans le contexte des navigateurs et nulle part ailleurs. Il n'y a pas de "fenêtre" dans nativescript, ni d'iframe. Si vous souhaitez vous moquez de certaines fonctionnalités, la création d'une propriété 'global.window' est totalement satisfaisante. En outre, une description plus précise de ce que vous tentez de réaliser nous permettra de vous donner des indications sur les points à examiner. – pkanev

+0

Merci @pkanev, Pouvez-vous partager le lien afin que je puisse le référer. – Deepika

Répondre

0

Nous traitons avec succès le contenu SCORM dans notre application NativeScript, mais cela nécessite un peu de hackery.

J'ai créé une classe d'utilitaires qui injectera dans le fichier d'entrée principal (index) du contenu SCORM un remplacement pour l'API de fenêtre.

Contexte:

  • Dans notre application, nous Décompresser les cours postaux aux appareils: documents/cours/UUID (c'est ce que l'identité fait référence)
  • Vous pouvez modifier le chemin si nécessaire pour votre mise en œuvre

Exemple d'utilisation de la classe de service:

const documents = fs.knownFolders.documents(); 
const destination = fs.path.join(documents.path, 'courses', this.media.identity); 
this._readAccessUrl = destination; 
const src = `file://${destination}`; 
if (fs.File.exists(destination)) { 
    SCORMUtils.readSCORMManifest(this.media.identity).then(fileName => { 
     this._src = `${src}/${fileName}`; 
     SCORMUtils.makeOfflineCompatible(fs.path.join(destination, fileName)) 
      .then(() => { 
       this._loading = false; 
      }); 
     this._loading = false; 
    }); 
} 

Classe utilitaire:

import { File, knownFolders } from 'tns-core-modules/file-system'; 

const SCORM_API = ` 
    <script type="text/javascript"> 
    (function() { 
     window.parent.API = (function() { 
      return { 
       LMSInitialize: function() { 
        if (window && window.webkit) { 
         window.webkit.messageHandlers.print.postMessage("LMSInitialize"); 
        } 
        return "true"; 
       }, 
       LMSCommit: function() { 
        if (window && window.webkit) { 
         window.webkit.messageHandlers.print.postMessage("LMSCommit"); 
        } 
        return "true"; 
       }, 
       LMSFinish: function() { 
        if (window && window.webkit) { 
         window.webkit.messageHandlers.print.postMessage("LMSFinish"); 
        } 
        return "true"; 
       }, 
       LMSGetValue: function (key) { 
        if (window && window.webkit) { 
         window.webkit.messageHandlers.print.postMessage("LMSGetValue"); 
        } 
        return ""; 
       }, 
       LMSSetValue: function (key, value) { 
        if (window && window.webkit) { 
         window.webkit.messageHandlers.print.postMessage("LMSSetValue"); 
        } 
        return "true"; 
       }, 
       LMSGetLastError: function() { 
        if (window && window.webkit) { 
         window.webkit.messageHandlers.print.postMessage("LMSGetLastError"); 
        } 
        return "0"; 
       }, 
       LMSGetErrorString: function (errorCode) { 
        if (window && window.webkit) { 
         window.webkit.messageHandlers.print.postMessage("LMSGetErrorString"); 
        } 
        return "No error"; 
       }, 
       LMSGetDiagnostic: function (errorCode) { 
        if (window && window.webkit) { 
         window.webkit.messageHandlers.print.postMessage("LMSGetDiagnostic"); 
        } 
        return "No error"; 
       } 
      } 
     })(); 
    })(); 
    </script> 
    </head> 
`; 

export class SCORMUtils { 

    /** 
    * Converts a SCORM course to be opened offline 
    * @param entryFile The main entry point determined by imsmanifest.xml 
    */ 
    static makeOfflineCompatible(entryFile: string) { 
     return new Promise((resolve, reject) => { 
      // Rewrite the entry file first 
      this._rewriteFile(entryFile) 
       .then(() => { 
        this._discoverHTMLEntry(entryFile) 
         .then(() => { 
          resolve(); 
         },() => { 
          console.error('Unable to rewrite alternative HTML entry'); 
          reject(); 
         }); 
       },() => { 
        console.error(`Unable to rewrite primary entry point: ${entryFile}`); 
        reject(); 
       }); 
     }); 
    } 

    /** 
    * Digests a SCORM Manifest file to determine the main point of entry 
    * for the course viewer. Normally this is a index.html file. 
    */ 
    static readSCORMManifest(identity: string): Promise<string> { 
     return new Promise((resolve, reject) => { 
      const manifestFile = knownFolders.documents() 
       .getFolder('courses') 
       .getFolder(identity) 
       .getFile('imsmanifest.xml'); 
      if (!File.exists(manifestFile.path)) { 
       alert({ 
        title: 'Error', 
        message: 'Course is missing imsmanifest.xml file', 
        okButtonText: 'Ok' 
       }); 
       return reject(); 
      } 
      const data = manifestFile.readTextSync(() => { 
       alert({ 
        title: 'Error', 
        message: 'Cannot open course.', 
        okButtonText: 'Ok' 
       }); 
       return reject(); 
      }); 
      const matches = data.match(/type="webcontent"+.+?href="(.*?)"/); 
      if (matches === null || matches.length < 1) { 
       alert({ 
        title: 'Error', 
        message: 'Invalid imsmanifest.xml file', 
        okButtonText: 'Ok' 
       }); 
      } 
      else { 
       resolve(matches[1]); 
      } 
     }); 
    } 

    /** 
    * Rewrites a file to be SCORM offline-compliant 
    * @param path The path of the file to re-write 
    */ 
    private static _rewriteFile(path: string) { 
     return new Promise((resolve, reject) => { 
      const entryFile = File.fromPath(path); 
      entryFile.readText() 
       .then(htmlText => { 
        this._injectOfflineAPI(htmlText) 
         .then(updatedHtml => { 
          entryFile.writeText(updatedHtml).then(() => { 
           resolve(); 
          },() => { 
           console.error(`Error writing to file: ${path}`); 
           reject(); 
          }); 
         }); 
       },() => { 
        console.error(`There was an entry reading the entry file at: ${path}`); 
        reject(); 
       }); 
     }); 
    } 

    /** 
    * Attempts to find another SCORM entry point for re-write 
    * @param mainEntry The main entry point to branch from 
    */ 
    private static _discoverHTMLEntry(mainEntry: string): Promise<any> { 
     return new Promise((resolve, reject) => { 
      const entryFile = File.fromPath(mainEntry); 
      entryFile.readText() 
       .then(htmlText => { 
        let htmlEntry = htmlText.match(/{"type":"html5","url":"(.*?)"}/); 
        if (htmlEntry === null || htmlEntry.length < 1) { 
         // Check for Articulate 
         htmlEntry = htmlText.match(/location\.href\.replace\("index_lms", "(.*?)"/); 
        } 
        if (htmlEntry !== null && htmlEntry.length > 0) { 
         let fileName = htmlEntry[1]; 
         if (fileName.indexOf('.html') === -1) { 
          fileName = `${fileName}.html`; 
         } 
         const directory = mainEntry.substr(0, mainEntry.lastIndexOf('/')); 
         const entryPoint = `${directory}/${fileName}`; 
         if (File.exists(entryPoint)) { 
          this._rewriteFile(entryPoint) 
           .then(() => { 
            resolve(); 
           },() => { 
            console.error('Error discovering main entry point.'); 
            reject(); 
           }); 
         } 
         else { 
          console.error(`Cannot find alternative entry point: ${entryPoint}`); 
          reject(); 
         } 
        } 
        else { 
         // This course does not have an alternative entry point 
         console.error('Course does not have an alternative entry, skipping...'); 
         resolve(); 
        } 
       },() => { 
        reject(); 
       }); 
     }); 
    } 

    /** 
    * Injects the extended SCORM API for offline-compatible viewing 
    * @param text The unmodified HTML source text 
    */ 
    private static _injectOfflineAPI(text: string): Promise<string> { 
     return new Promise((resolve, reject) => { 
      // Prevent multiple rewrites of the same file 
      if (this._isConverted(text)) { 
       return resolve(text); 
      } 
      // Finds the end of the head tag for script injection 
      const head = text.match(/<\/head>/gi); 
      if (head !== null && head.length > 0) { 
       resolve(text.replace(head.toString(), SCORM_API)); 
      } 
      else { 
       console.error('Unable to parse incoming HTML for head tag.'); 
       reject({ 
        message: 'Unable to parse HTML' 
       }); 
      } 
     }); 
    } 

    /** 
    * Checks if the HTML has already been converted for offline-viewing 
    * @param text The incoming HTML source text 
    */ 
    private static _isConverted(text: string) { 
     const match = text.match(/window.parent.API/); 
     return match !== null && match.length > 0; 
    } 

} 
+0

Hey @Sean Comment communiquez-vous des données, comme disent que LMSGetValue est déclenché. – Deepika

+0

L'implémentation de WKWebView permet d'écouter les messages émis depuis le cadre: https://github.com/triniwiz/nativescript-webkit-webview/blob/master/src/webkit-webview.ios.ts#L384. Nous ne les avons pas encore pris en compte, mais j'ai ajouté ces hooks postMessage pour les futures implémentations. –

+0

J'ai installé le plugin market.nativescript.org/plugins/nativescript-webview-interfa ce qui m'aide à communiquer et à retourner de la valeur du côté de nativescript. – Deepika